Completed
Push — master ( 3845e2...5afe3b )
by Jean-Christophe
02:10
created

CRUDController   F

Complexity

Total Complexity 66

Size/Duplication

Total Lines 406
Duplicated Lines 7.14 %

Coupling/Cohesion

Components 1
Dependencies 13

Importance

Changes 0
Metric Value
wmc 66
lcom 1
cbo 13
dl 29
loc 406
rs 3.12
c 0
b 0
f 0

29 Methods

Rating   Name   Duplication   Size   Complexity  
A index() 0 8 2
A getInstances() 0 15 3
A _getInstancesFilter() 0 3 1
A search() 0 5 1
A refresh_() 0 26 5
A _renderDataTableForRefresh() 0 6 2
A edit() 10 10 2
A newModel() 11 11 2
A display() 0 15 2
A _edit() 0 20 2
A _showModel() 0 6 2
B delete() 4 34 6
A _deleteMultiple() 0 21 4
A refreshTable() 0 5 1
A update() 4 25 4
A refreshInstance() 0 8 3
B showDetail() 0 34 8
A detailClick() 0 3 1
A getModelInstance() 0 12 2
A getAdminData() 0 3 1
A _getAdminData() 0 3 1
A getModelViewer() 0 3 1
A _getModelViewer() 0 3 1
A getFiles() 0 3 1
A _getFiles() 0 3 1
A getEvents() 0 3 1
A _getEvents() 0 3 1
A getSingleton() 0 6 2
A crudLoadView() 0 18 3

How to fix   Duplicated Code    Complexity   

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:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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\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
use Ajax\semantic\html\collections\HtmlMessage;
17
18
abstract class CRUDController extends ControllerBase implements HasModelViewerInterface{
19
	use MessagesTrait;
20
	protected $model;
21
	protected $modelViewer;
22
	protected $events;
23
	protected $crudFiles;
24
	protected $adminDatas;
25
	protected $activePage;
26
	
27
	/**
28
	 * Default page : list all objects
29
	 */
30
	public function index() {
31
		$objects=$this->getInstances($totalCount);
32
		$modal=($this->_getModelViewer()->isModal($objects,$this->model))?"modal":"no";
33
		$this->_getModelViewer()->getModelDataTable($objects, $this->model,$totalCount);
34
		$this->jquery->getOnClick ( "#btAddNew", $this->_getBaseRoute() . "/newModel/" . $modal, "#frm-add-update",["hasLoader"=>"internal"] );
35
		$this->_getEvents()->onDisplayElements();
36
		$this->crudLoadView($this->_getFiles()->getViewIndex(), [ "classname" => $this->model ,"messages"=>$this->jquery->semantic()->matchHtmlComponents(function($compo){return $compo instanceof HtmlMessage;})]);		
1 ignored issue
show
Bug introduced by
The class Ajax\semantic\html\collections\HtmlMessage does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
37
	}
38
	
39
	protected function getInstances(&$totalCount,$page=1,$id=null){
40
		$this->activePage=$page;
41
		$model=$this->model;
42
		$condition=$this->_getInstancesFilter($model);
43
		$totalCount=DAO::count($model,$condition);
44
		$recordsPerPage=$this->_getModelViewer()->recordsPerPage($model,$totalCount);
45
		if(is_numeric($recordsPerPage)){
46
			if(isset($id)){
47
				$rownum=DAO::getRownum($model, $id);
48
				$this->activePage=Pagination::getPageOfRow($rownum,$recordsPerPage);
49
			}
50
			return DAO::paginate($model,$this->activePage,$recordsPerPage,$condition);
51
		}
52
		return DAO::getAll($model,$condition);
53
	}
54
	
55
	public function _getInstancesFilter($model){
56
		return "1=1";
57
	}
58
	
59
	protected function search($model,$search){
60
		$fields=$this->_getAdminData()->getSearchFieldNames($model);
61
		$condition=$this->_getInstancesFilter($model);
62
		return CRUDHelper::search($model, $search, $fields,$condition);
63
	}
64
	
65
	public function refresh_(){
66
		$model=$this->model;
67
		if(isset($_POST["s"])){
68
			$instances=$this->search($model, $_POST["s"]);
69
		}else{
70
			$page=URequest::post("p",1);
71
			$instances=$this->getInstances($totalCount,$page);
72
		}
73
		if(!isset($totalCount)){
74
			$totalCount=DAO::count($model,$this->_getInstancesFilter($model));
75
		}
76
		$recordsPerPage=$this->_getModelViewer()->recordsPerPage($model,$totalCount);
77
		$grpByFields=$this->_getModelViewer()->getGroupByFields();
78
		if(isset($recordsPerPage)){
79
			if(!is_array($grpByFields)){
80
				UResponse::asJSON();
81
				$responseFormatter=new ResponseFormatter();
82
				print_r($responseFormatter->getJSONDatas($instances));
83
			}else{
84
				$this->_renderDataTableForRefresh($instances, $model,$totalCount);
85
			}
86
		}else{
87
			$this->jquery->execAtLast('$("#search-query-content").html("'.$_POST["s"].'");$("#search-query").show();$("#table-details").html("");');
88
			$this->_renderDataTableForRefresh($instances, $model,$totalCount);
89
		}
90
	}
91
	
92
	private function _renderDataTableForRefresh($instances,$model,$totalCount){
93
		$this->formModal=($this->_getModelViewer()->isModal($instances,$model))? "modal" : "no";
94
		$compo= $this->_getModelViewer()->getModelDataTable($instances, $model,$totalCount)->refresh(["tbody"]);
95
		$this->_getEvents()->onDisplayElements();
96
		$this->jquery->renderView("@framework/main/component.html",["compo"=>$compo]);
97
	}
98
	
99
	/**
100
	 * Edits an instance
101
	 * @param string $modal Accept "no" or "modal" for a modal dialog
102
	 * @param string $ids the primary value(s)
103
	 */
104 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...
105
		if(URequest::isAjax()){
106
			$instance=$this->getModelInstance($ids);
107
			$instance->_new=false;
108
			$this->_edit($instance, $modal);
109
		}else{
110
			$this->jquery->execAtLast("$('._edit[data-ajax={$ids}]').trigger('click');");
111
			$this->index();
112
		}
113
	}
114
	/**
115
	 * Adds a new instance and edits it
116
	 * @param string $modal Accept "no" or "modal" for a modal dialog
117
	 */
118 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...
119
		if(URequest::isAjax()){
120
			$model=$this->model;
121
			$instance=new $model();
122
			$instance->_new=true;
123
			$this->_edit($instance, $modal);
124
		}else{
125
			$this->jquery->execAtLast("$('.ui.button._new').trigger('click');");
126
			$this->index();
127
		}
128
	}
129
	
130
	/**
131
	 * Displays an instance
132
	 * @param string $modal
133
	 * @param string $ids
134
	 */
135
	public function display($modal="no",$ids=""){
136
		if(URequest::isAjax()){
137
			$instance=$this->getModelInstance($ids);
138
			$key=OrmUtils::getFirstKeyValue($instance);
139
			$this->jquery->execOn("click","._close",'$("#table-details").html("");$("#dataTable").show();');
140
			$this->jquery->getOnClick("._edit", $this->_getBaseRoute()."/edit/".$modal."/".$key,"#frm-add-update");
141
			$this->jquery->getOnClick("._delete", $this->_getBaseRoute()."/delete/".$key,"#table-messages");
142
			
143
			$this->_getModelViewer()->getModelDataElement($instance, $this->model,$modal);
144
			$this->jquery->renderView($this->_getFiles()->getViewDisplay(), [ "classname" => $this->model,"instance"=>$instance,"pk"=>$key ]);
145
		}else{
146
			$this->jquery->execAtLast("$('._display[data-ajax={$ids}]').trigger('click');");
147
			$this->index();
148
		}
149
	}
150
	
151
	protected function _edit($instance, $modal="no") {
152
		$_SESSION["instance"]=$instance;
153
		$modal=($modal == "modal");
154
		$form=$this->_getModelViewer()->getForm("frmEdit", $instance);
155
		$this->jquery->click("#action-modal-frmEdit-0", "$('#frmEdit').form('submit');", false);
156
		if (!$modal) {
157
			$this->jquery->click("#bt-cancel", "$('#form-container').transition('drop');");
158
			$this->jquery->compile($this->view);
159
			$this->loadView($this->_getFiles()->getViewForm(), [ "modal" => $modal ]);
160
		} else {
161
			$this->jquery->exec("$('#modal-frmEdit').modal('show');", true);
162
			$form=$form->asModal(\get_class($instance));
163
			$form->setActions([ "Okay","Cancel" ]);
164
			$btOkay=$form->getAction(0);
165
			$btOkay->addClass("green")->setValue("Validate modifications");
166
			$form->onHidden("$('#modal-frmEdit').remove();");
167
			echo $form->compile($this->jquery, $this->view);
168
			echo $this->jquery->compile($this->view);
169
		}
170
	}
171
	
172
	protected function _showModel($id=null) {
173
		$model=$this->model;
174
		$datas=$this->getInstances($totalCount,1,$id);
175
		$this->formModal=($this->_getModelViewer()->isModal($datas,$model))? "modal" : "no";
176
		return $this->_getModelViewer()->getModelDataTable($datas, $model,$totalCount,$this->activePage);
177
	}
178
	
179
	/**
180
	 * Deletes an instance
181
	 * @param mixed $ids
182
	 */
183
	public function delete($ids) {
184
		if(URequest::isAjax()){
185
			$instance=$this->getModelInstance($ids);
186 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...
187
				$instanceString=$instance . "";
188
			else
189
				$instanceString=get_class($instance);
190
			if (sizeof($_POST) > 0) {
191
				try{
192
					if (DAO::remove($instance)) {
0 ignored issues
show
Bug introduced by
It seems like $instance defined by $this->getModelInstance($ids) on line 185 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...
193
						$message=new CRUDMessage("Deletion of `<b>" . $instanceString . "</b>`","Deletion","info","info circle",4000);
194
						$message=$this->_getEvents()->onSuccessDeleteMessage($message);
195
						$this->jquery->exec("$('._element[data-ajax={$ids}]').remove();", true);
196
					} else {
197
						$message=new CRUDMessage("Can not delete `" . $instanceString . "`","Deletion","warning","warning circle");
198
						$message=$this->_getEvents()->onErrorDeleteMessage($message);
199
					}
200
				}catch (\Exception $e){
201
					$message=new CRUDMessage("Exception : can not delete `" . $instanceString . "`","Exception", "warning", "warning");
202
					$message=$this->_getEvents()->onErrorDeleteMessage($message);
203
				}
204
				$message=$this->_showSimpleMessage($message);
205
			} else {
206
				$message=new CRUDMessage("Do you confirm the deletion of `<b>" . $instanceString . "</b>`?", "Remove confirmation","error");
207
				$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...
208
				$message=$this->_showConfMessage($message, $this->_getBaseRoute() . "/delete/{$ids}", "#table-messages", $ids);
209
			}
210
			echo $message;
211
			echo $this->jquery->compile($this->view);
212
		}else{
213
			$this->jquery->execAtLast("$('._delete[data-ajax={$ids}]').trigger('click');");
214
			$this->index();
215
		}
216
	}
217
	
218
	/**
219
	 * Helper to delete multiple objects
220
	 * @param mixed $data
221
	 * @param string $action
222
	 * @param string $target the css selector for refreshing
223
	 * @param callable|string $condition the callback for generating the SQL where (for deletion) with the parameter data, or a simple string
224
	 */
225
	protected function _deleteMultiple($data,$action,$target,$condition){
226
		if(URequest::isPost()){
227
			if(is_callable($condition)){
228
				$condition=$condition($data);
229
			}
230
			$rep=DAO::deleteAll($this->model, $condition);
231
			if($rep){
232
				$message=new CRUDMessage("Deleting {count} objects","Deletion","info","info circle",4000);
233
				$message=$this->_getEvents()->onSuccessDeleteMultipleMessage($message);
234
				$message->parseContent(["count"=>$rep]);
235
			}
236
			$this->_showSimpleMessage($message,"delete-all");
0 ignored issues
show
Bug introduced by
The variable $message does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
237
			$this->index();
238
		}else{
239
			$message=new CRUDMessage("Do you confirm the deletion of this objects?", "Remove confirmation","error");
240
			$this->_getEvents()->onConfDeleteMultipleMessage($message,$data);
241
			$message=$this->_showConfMessage($message, $this->_getBaseRoute() . "/{$action}/{$data}",$target, $data,["jqueryDone"=>"replaceWith"]);
242
			echo $message;
243
			echo $this->jquery->compile($this->view);
244
		}
245
	}
246
	
247
248
	
249
	public function refreshTable($id=null) {
250
		$compo= $this->_showModel($id);
251
		$this->jquery->execAtLast('$("#table-details").html("");');
252
		$this->jquery->renderView("@framework/main/component.html",["compo"=>$compo]);	
253
	}
254
	
255
	/**
256
	 * Updates an instance from the data posted in a form
257
	 */
258
	public function update() {
259
		$message=new CRUDMessage("Modifications were successfully saved", "Updating");
260
		$instance=@$_SESSION["instance"];
261
		$isNew=$instance->_new;
262
		try{
263
			$updated=CRUDHelper::update($instance, $_POST,$this->_getAdminData()->getUpdateManyToOneInForm(),$this->_getAdminData()->getUpdateManyToManyInForm());
264
			if($updated){
265
				$message->setType("success")->setIcon("check circle outline");
266
				$message=$this->_getEvents()->onSuccessUpdateMessage($message);
267
				$this->refreshInstance($instance,$isNew);
268
			} else {
269
				$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...
270
				$message=$this->_getEvents()->onErrorUpdateMessage($message);
271
			}
272
		}catch(\Exception $e){
273 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...
274
				$instanceString=$instance . "";
275
			else
276
				$instanceString=get_class($instance);
277
			$message=new CRUDMessage("Exception : can not update `" . $instanceString . "`","Exception", "warning", "warning");
278
			$message=$this->_getEvents()->onErrorUpdateMessage($message);
279
		}
280
		echo $this->_showSimpleMessage($message,"updateMsg");
281
		echo $this->jquery->compile($this->view);
282
	}
283
	
284
	protected function refreshInstance($instance,$isNew){
285
		if($this->_getAdminData()->refreshPartialInstance() && !$isNew){
286
			$this->jquery->setJsonToElement(OrmUtils::objectAsJSON($instance));
287
		}else{
288
			$pk=OrmUtils::getFirstKeyValue($instance);
289
			$this->jquery->get($this->_getBaseRoute() . "/refreshTable/".$pk, "#lv", [ "jqueryDone" => "replaceWith" ]);
290
		}
291
	}
292
	
293
	/**
294
	 * Shows associated members with foreign keys
295
	 * @param mixed $ids
296
	 */
297
	public function showDetail($ids) {
298
		if(URequest::isAjax()){
299
			$instance=$this->getModelInstance($ids);
300
			$viewer=$this->_getModelViewer();
301
			$hasElements=false;
302
			$model=$this->model;
303
			$fkInstances=CRUDHelper::getFKIntances($instance, $model);
304
			$semantic=$this->jquery->semantic();
305
			$grid=$semantic->htmlGrid("detail");
306
			if (sizeof($fkInstances) > 0) {
307
				$wide=intval(16 / sizeof($fkInstances));
308
				if ($wide < 4)
309
					$wide=4;
310
					foreach ( $fkInstances as $member=>$fkInstanceArray ) {
311
						$element=$viewer->getFkMemberElementDetails($member,$fkInstanceArray["objectFK"],$fkInstanceArray["fkClass"],$fkInstanceArray["fkTable"]);
312
						if (isset($element)) {
313
							$grid->addCol($wide)->setContent($element);
314
							$hasElements=true;
315
						}
316
					}
317
					if ($hasElements)
318
						echo $grid;
319
						$url=$this->_getEvents()->onDetailClickURL($this->model);
320
					if(UString::isNotNull($url)){
321
						$this->detailClick($url);
322
					}
323
					echo $this->jquery->compile($this->view);
324
			}
325
		}else{
326
			$this->jquery->execAtLast("$('tr[data-ajax={$ids}]').trigger('click');");
327
			$this->index();
328
		}
329
330
	}
331
	
332
	public function detailClick($url) {
333
		$this->jquery->postOnClick(".showTable", $this->_getBaseRoute() . "/".$url,"{}", "#divTable", [ "attr" => "data-ajax","ajaxTransition" => "random" ]);
334
	}
335
	
336
	private function getModelInstance($ids) {
337
		$ids=\explode("_", $ids);
338
		$instance=DAO::getOne($this->model, $ids);
339
		if(isset($instance)){
340
			return $instance;
341
		}
342
		$message=new CRUDMessage("This object does not exist!","Get object","warning","warning circle");
343
		$message=$this->_getEvents()->onNotFoundMessage($message);
344
		echo $this->_showSimpleMessage($message);
345
		echo $this->jquery->compile($this->view);
346
		exit(1);
347
	}
348
	
349
	/**
350
	 * To override for defining a new adminData
351
	 * @return CRUDDatas
352
	 */
353
	protected function getAdminData ():CRUDDatas{
354
		return new CRUDDatas();
355
	}
356
	
357
	public function _getAdminData ():CRUDDatas{
358
		return $this->getSingleton($this->modelViewer,"getAdminData");
359
	}
360
	
361
	/**
362
	 * To override for defining a new ModelViewer
363
	 * @return ModelViewer
364
	 */
365
	protected function getModelViewer ():ModelViewer{
366
		return new ModelViewer($this);
367
	}
368
	
369
	private function _getModelViewer():ModelViewer{
370
		return $this->getSingleton($this->modelViewer,"getModelViewer");
371
	}
372
	
373
	/**
374
	 * To override for changing view files
375
	 * @return CRUDFiles
376
	 */
377
	protected function getFiles ():CRUDFiles{
378
		return new CRUDFiles();
379
	}
380
	
381
	private function _getFiles():CRUDFiles{
382
		return $this->getSingleton($this->crudFiles,"getFiles");
383
	}
384
	
385
	/**
386
	 * To override for changing events
387
	 * @return CRUDEvents
388
	 */
389
	protected function getEvents ():CRUDEvents{
390
		return new CRUDEvents($this);
391
	}
392
	
393
	private function _getEvents():CRUDEvents{
394
		return $this->getSingleton($this->events,"getEvents");
395
	}
396
	
397
	private function getSingleton($value, $method) {
398
		if (! isset ( $value )) {
399
			$value = $this->$method ();
400
		}
401
		return $value;
402
	}
403
	
404
	private function crudLoadView($viewName,$vars=[]){
405
		$this->_getEvents()->beforeLoadView($viewName,$vars);
406
		if(!URequest::isAjax()){
407
			$files=$this->_getFiles();
408
			$mainTemplate=$files->getBaseTemplate();
409
			if(isset($mainTemplate)){
410
				$vars["_viewname"]=$viewName;
411
				$vars["_base"]=$mainTemplate;
412
				$this->jquery->renderView($files->getViewBaseTemplate(),$vars);
413
			}else{
414
				$vars["hasScript"]=true;
415
				$this->jquery->renderView($viewName,$vars);
416
			}
417
		}else{
418
			$vars["hasScript"]=true;
419
			$this->jquery->renderView($viewName,$vars);
420
		}
421
	}
422
423
}
424