Test Failed
Pull Request — master (#97)
by Gildonei
03:38
created

ModelViewer   B

Complexity

Total Complexity 47

Size/Duplication

Total Lines 407
Duplicated Lines 0 %

Test Coverage

Coverage 89.09%

Importance

Changes 0
Metric Value
wmc 47
eloc 142
dl 0
loc 407
ccs 147
cts 165
cp 0.8909
rs 8.64
c 0
b 0
f 0

25 Methods

Rating   Name   Duplication   Size   Complexity  
A addEditMemberFonctionality() 0 5 3
A getFkElement() 0 2 1
A showDetailsOnDataTableClick() 0 2 1
A getDataTableInstance() 0 18 3
A getGroupByFields() 0 2 1
A getModelDataTable() 0 20 1
A getFkHeaderElementDetails() 0 2 1
A getElementCaptions() 0 2 1
A onConfirmButtons() 0 1 1
A addAllButtons() 0 15 1
A recordsPerPage() 0 4 2
A getDataTableRowButtons() 0 2 1
A getFkList() 0 4 1
A onDisplayFkElementListDetails() 0 1 1
A getFkListDetails() 0 5 1
A getModelDataElement() 0 22 3
A getFkHeaderListDetails() 0 2 1
A getFkMemberElement() 0 22 6
A onDataTableRowButton() 0 1 1
A displayFkElementList() 0 1 1
A getFkElementDetails() 0 2 1
B getFkMemberElementDetails() 0 27 7
A setDataTableAttributes() 0 25 5
A __construct() 0 3 1
A getCaptions() 0 2 1

How to fix   Complexity   

Complex Class

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

1
<?php
2
3
namespace Ubiquity\controllers\crud\viewers;
4
5
use Ajax\semantic\html\elements\HtmlButton;
6
use Ajax\semantic\html\elements\HtmlHeader;
7
use Ajax\semantic\html\elements\HtmlLabel;
8
use Ajax\semantic\widgets\datatable\DataTable;
9
use Ajax\semantic\widgets\datatable\PositionInTable;
10
use Ubiquity\controllers\crud\CRUDHelper;
11
use Ubiquity\controllers\crud\interfaces\HasModelViewerInterface;
12
use Ubiquity\controllers\crud\viewers\traits\FormModelViewerTrait;
13
use Ubiquity\orm\OrmUtils;
14
use Ubiquity\utils\base\UString;
15
16
/**
17
 * Associated with a CRUDController class
18
 * Responsible of the display
19
 *
20
 * @author jc
21
 *
22
 */
23
class ModelViewer {
24
	use FormModelViewerTrait;
25
	/**
26
	 *
27
	 * @var \Ajax\JsUtils
28
	 */
29
	private $jquery;
30
31
	/**
32
	 *
33
	 * @var HasModelViewerInterface
34
	 */
35
	protected $controller;
36
37 7
	public function __construct(HasModelViewerInterface $controller) {
38 7
		$this->jquery = $controller->jquery;
39 7
		$this->controller = $controller;
40 7
	}
41
42
	/**
43
	 * Returns a DataElement object for displaying the instance
44
	 * Used in the display method of the CrudController
45
	 * in display route
46
	 *
47
	 * @param object $instance
48
	 * @param string $model The model class name (long name)
49
	 * @param boolean $modal
50
	 * @return \Ajax\semantic\widgets\dataelement\DataElement
51
	 */
52 2
	public function getModelDataElement($instance, $model, $modal) {
53 2
		$semantic = $this->jquery->semantic ();
54 2
		$fields = $this->controller->_getAdminData ()->getElementFieldNames ( $model );
55
56 2
		$dataElement = $semantic->dataElement ( "de", $instance );
57 2
		$pk = OrmUtils::getFirstKeyValue ( $instance );
58
		$dataElement->getInstanceViewer ()->setIdentifierFunction ( function () use ($pk) {
59 2
			return $pk;
60 2
		} );
61 2
		$dataElement->setFields ( $fields );
62 2
		$dataElement->setCaptions ( $this->getElementCaptions ( $fields, $model, $instance ) );
63
64 2
		$fkInstances = CRUDHelper::getFKIntances ( $instance, $model );
65 2
		foreach ( $fkInstances as $member => $fkInstanceArray ) {
66 2
			if (array_search ( $member, $fields ) !== false) {
67
				$dataElement->setValueFunction ( $member, function () use ($fkInstanceArray, $member) {
68 2
					return $this->getFkMemberElement ( $member, $fkInstanceArray ["objectFK"], $fkInstanceArray ["fkClass"], $fkInstanceArray ["fkTable"] );
69 2
				} );
70
			}
71
		}
72 2
		$this->addEditMemberFonctionality ( "dataElement" );
73 2
		return $dataElement;
74
	}
75
76
	/**
77
	 * Returns the captions for DataElement fields
78
	 * in display route
79
	 *
80
	 * @param array $captions
81
	 * @param string $className
82
	 */
83 2
	public function getElementCaptions($captions, $className, $instance) {
84 2
		return array_map ( "ucfirst", $captions );
85
	}
86
87
	/**
88
	 * Returns the dataTable responsible for displaying instances of the model
89
	 *
90
	 * @param array $instances objects to display
91
	 * @param string $model model class name (long name)
92
	 * @return DataTable
93
	 */
94 7
	public function getModelDataTable($instances, $model, $totalCount, $page = 1) {
95 7
		$adminRoute = $this->controller->_getBaseRoute ();
96 7
		$files = $this->controller->_getFiles ();
97 7
		$dataTable = $this->getDataTableInstance ( $instances, $model, $totalCount, $page );
98 7
		$attributes = $this->controller->_getAdminData ()->getFieldNames ( $model );
99 7
		$this->setDataTableAttributes ( $dataTable, $attributes, $model, $instances );
100 7
		$dataTable->setCaptions ( $this->getCaptions ( $attributes, $model ) );
101
102 7
		$dataTable->addClass ( "small very compact" );
103 7
		$lbl = new HtmlLabel ( "search-query", "<span id='search-query-content'></span>" );
104 7
		$icon = $lbl->addIcon ( "delete", false );
105 7
		$lbl->wrap ( "<span>", "</span>" );
106 7
		$lbl->setProperty ( "style", "display: none;" );
107 7
		$icon->getOnClick ( $adminRoute . $files->getRouteRefreshTable (), "#lv", [ "jqueryDone" => "replaceWith","hasLoader" => "internal" ] );
108
109 7
		$dataTable->addItemInToolbar ( $lbl );
110 7
		$dataTable->addSearchInToolbar ();
111 7
		$dataTable->setToolbarPosition ( PositionInTable::FOOTER );
112 7
		$dataTable->getToolbar ()->setSecondary ();
113 7
		return $dataTable;
114
	}
115
116 7
	public function setDataTableAttributes(DataTable $dataTable, $attributes, $model, $instances, $selector = null) {
117 7
		$modal = ($this->isModal ( $instances, $model ) ? "modal" : "no");
118
119 7
		$adminRoute = $this->controller->_getBaseRoute ();
120 7
		$files = $this->controller->_getFiles ();
121 7
		$dataTable->setButtons ( $this->getDataTableRowButtons () );
122 7
		$dataTable->setFields ( $attributes );
123 7
		if (array_search ( "password", $attributes ) !== false) {
124
			$dataTable->setValueFunction ( "password", function ($v) {
125 1
				return UString::mask ( $v );
126 1
			} );
127
		}
128 7
		$dataTable->setIdentifierFunction ( CRUDHelper::getIdentifierFunction ( $model ) );
129
130 7
		if (! isset ( $selector )) {
131 7
			if ($this->showDetailsOnDataTableClick ()) {
132 7
				$dataTable->getOnRow ( "click", $adminRoute . $files->getRouteDetails (), "#table-details", [ "selector" => $selector,"attr" => "data-ajax","hasLoader" => false,"jsCondition" => "!event.detail || event.detail==1","jsCallback" => "return false;" ] );
133 7
				$dataTable->setActiveRowSelector ( "active" );
134
			}
135
136 7
			$dataTable->setUrls ( [ "refresh" => $adminRoute . $files->getRouteRefresh (),"delete" => $adminRoute . $files->getRouteDelete (),"edit" => $adminRoute . $files->getRouteEdit () . "/" . $modal,"display" => $adminRoute . $files->getRouteDisplay () . "/" . $modal ] );
137 7
			$dataTable->setTargetSelector ( [ "delete" => "#table-messages","edit" => "#frm-add-update","display" => "#table-details" ] );
138 7
			$this->addEditMemberFonctionality ( "dataTable" );
139
		}
140 7
		$this->addAllButtons ( $dataTable, $attributes );
141 7
	}
142
143 7
	public function addEditMemberFonctionality($part) {
144 7
		if (($editMemberParams = $this->getEditMemberParams ()) !== false) {
145 7
			if (isset ( $editMemberParams [$part] )) {
146 7
				$params = $editMemberParams [$part];
147 7
				$params->compile ( $this->controller->_getBaseRoute (), $this->jquery, $part );
148
			}
149
		}
150 7
	}
151
152
	/**
153
	 *
154
	 * @param string $model The model class name (long name)
155
	 * @param number $totalCount The total count of objects
156
	 * @return void|number default : 6
157
	 */
158 7
	public function recordsPerPage($model, $totalCount = 0) {
159 7
		if ($totalCount > 6)
160 2
			return 6;
161 5
		return;
162
	}
163
164
	/**
165
	 * Returns the fields on which a grouping is performed
166
	 */
167 3
	public function getGroupByFields() {
168 3
		return;
169
	}
170
171
	/**
172
	 * Returns the dataTable instance for dispaying a list of object
173
	 *
174
	 * @param array $instances
175
	 * @param string $model
176
	 * @param number $totalCount
177
	 * @param number $page
178
	 * @return DataTable
179
	 */
180 7
	protected function getDataTableInstance($instances, $model, $totalCount, $page = 1): DataTable {
181 7
		$semantic = $this->jquery->semantic ();
182 7
		$recordsPerPage = $this->recordsPerPage ( $model, $totalCount );
183 7
		if (is_numeric ( $recordsPerPage )) {
184 2
			$grpByFields = $this->getGroupByFields ();
185 2
			if (is_array ( $grpByFields )) {
186
				$dataTable = $semantic->dataTable ( "lv", $model, $instances );
187
				$dataTable->setGroupByFields ( $grpByFields );
188
			} else {
189 2
				$dataTable = $semantic->jsonDataTable ( "lv", $model, $instances );
190
			}
191 2
			$dataTable->paginate ( $page, $totalCount, $recordsPerPage, 5 );
192 2
			$dataTable->onActiveRowChange ( '$("#table-details").html("");' );
193 2
			$dataTable->onSearchTerminate ( '$("#search-query-content").html(data);$("#search-query").show();$("#table-details").html("");' );
194
		} else {
195 5
			$dataTable = $semantic->dataTable ( "lv", $model, $instances );
196
		}
197 7
		return $dataTable;
198
	}
199
200
	/**
201
	 * Returns an array of buttons ["display","edit","delete"] to display for each row in dataTable
202
	 *
203
	 * @return string[]
204
	 */
205 2
	protected function getDataTableRowButtons() {
206 2
		return [ "edit","delete" ];
207
	}
208
209 7
	public function addAllButtons(DataTable $dataTable, $attributes) {
210
		$dataTable->onPreCompile ( function () use (&$dataTable) {
211 7
			$dataTable->getHtmlComponent ()->colRightFromRight ( 0 );
212 7
		} );
213
		$dataTable->addAllButtons ( false, [ "ajaxTransition" => "random" ], function ($bt) {
214 5
			$bt->addClass ( "circular" );
215 5
			$this->onDataTableRowButton ( $bt );
216
		}, function ($bt) {
217 7
			$bt->addClass ( "circular" );
218 7
			$this->onDataTableRowButton ( $bt );
219
		}, function ($bt) {
220 7
			$bt->addClass ( "circular" );
221 7
			$this->onDataTableRowButton ( $bt );
222 7
		} );
223 7
		$dataTable->setDisplayBehavior ( [ "jsCallback" => '$("#dataTable").hide();',"ajaxTransition" => "random" ] );
224 7
	}
225
226
	/**
227
	 * To override for modifying the dataTable row buttons
228
	 *
229
	 * @param HtmlButton $bt
230
	 */
231 7
	public function onDataTableRowButton(HtmlButton $bt) {
232 7
	}
233
234
	/**
235
	 * To override for modifying the showConfMessage dialog buttons
236
	 *
237
	 * @param HtmlButton $confirmBtn The confirmation button
238
	 * @param HtmlButton $cancelBtn The cancellation button
239
	 */
240 3
	public function onConfirmButtons(HtmlButton $confirmBtn, HtmlButton $cancelBtn) {
241 3
	}
242
243
	/**
244
	 * Returns the captions for list fields in showTable action
245
	 *
246
	 * @param array $captions
247
	 * @param string $className
248
	 */
249 7
	public function getCaptions($captions, $className) {
250 7
		return \array_map ( "ucfirst", $captions );
251
	}
252
253
	/**
254
	 * Returns the header for a single foreign object (element is an instance, issue from ManyToOne), (from DataTable)
255
	 *
256
	 * @param string $member
257
	 * @param string $className
258
	 * @param object $object
259
	 * @return HtmlHeader
260
	 */
261
	public function getFkHeaderElementDetails($member, $className, $object) {
262
		return new HtmlHeader ( "", 4, $member, "content" );
263
	}
264
265
	/**
266
	 * Returns the header for a list of foreign objects (issue from oneToMany or ManyToMany), (from DataTable)
267
	 *
268
	 * @param string $member
269
	 * @param string $className
270
	 * @param array $list
271
	 * @return HtmlHeader
272
	 */
273 1
	public function getFkHeaderListDetails($member, $className, $list) {
274 1
		return new HtmlHeader ( "", 4, $member . " (" . \count ( $list ) . ")", "content" );
275
	}
276
277
	/**
278
	 * Returns a component for displaying a single foreign object (manyToOne relation), (from DataTable)
279
	 *
280
	 * @param string $member
281
	 * @param string $className
282
	 * @param object $object
283
	 * @return \Ajax\common\html\BaseHtml
284
	 */
285
	public function getFkElementDetails($member, $className, $object) {
286
		return $this->jquery->semantic ()->htmlLabel ( "element-" . $className . "." . $member, $object . "" );
287
	}
288
289
	/**
290
	 * Returns a list component for displaying a collection of foreign objects (*ToMany relations), (from DataTable)
291
	 *
292
	 * @param string $member
293
	 * @param string $className
294
	 * @param array|\Traversable $list
295
	 * @return \Ajax\common\html\HtmlCollection
296
	 */
297 1
	public function getFkListDetails($member, $className, $list) {
298 1
		$element = $this->jquery->semantic ()->htmlList ( "list-" . $className . "." . $member );
299 1
		$element->setMaxVisible ( 15 );
300
301 1
		return $element->addClass ( "animated divided celled" );
302
	}
303
304
	/**
305
	 * Returns a component for displaying a foreign object (from DataTable)
306
	 *
307
	 * @param string $memberFK
308
	 * @param mixed $objectFK
309
	 * @param string $fkClass
310
	 * @param string $fkTable
311
	 * @return \Ajax\semantic\html\elements\HtmlHeader[]|\Ajax\common\html\BaseHtml[]|NULL
312
	 */
313 1
	public function getFkMemberElementDetails($memberFK, $objectFK, $fkClass, $fkTable) {
314 1
		$_fkClass = str_replace ( "\\", ".", $fkClass );
315 1
		$header = new HtmlHeader ( "", 4, $memberFK, "content" );
316 1
		if (is_array ( $objectFK ) || $objectFK instanceof \Traversable) {
317 1
			$header = $this->getFkHeaderListDetails ( $memberFK, $fkClass, $objectFK );
318 1
			$element = $this->getFkListDetails ( $memberFK, $fkClass, $objectFK );
319 1
			foreach ( $objectFK as $oItem ) {
320 1
				if (method_exists ( $oItem, "__toString" )) {
321 1
					$id = (CRUDHelper::getIdentifierFunction ( $fkClass )) ( 0, $oItem );
322 1
					$item = $element->addItem ( $oItem . "" );
323 1
					$item->setProperty ( "data-ajax", $_fkClass . "||" . $id );
324 1
					$item->addClass ( "showTable" );
325 1
					$this->onDisplayFkElementListDetails ( $item, $memberFK, $fkClass, $oItem );
326
				}
327
			}
328
		} else {
329
			if (method_exists ( $objectFK, "__toString" )) {
330
				$header = $this->getFkHeaderElementDetails ( $memberFK, $fkClass, $objectFK );
331
				$id = (CRUDHelper::getIdentifierFunction ( $fkClass )) ( 0, $objectFK );
332
				$element = $this->getFkElementDetails ( $memberFK, $fkClass, $objectFK );
333
				$element->setProperty ( "data-ajax", $_fkClass . "||" . $id )->addClass ( "showTable" );
334
			}
335
		}
336 1
		if (isset ( $element )) {
337 1
			return [ $header,$element ];
338
		}
339
		return null;
340
	}
341
342
	/**
343
	 * To modify for displaying an element in a list component of foreign objects (from DataTable)
344
	 *
345
	 * @param \Ajax\common\html\HtmlDoubleElement $element
346
	 * @param string $member
347
	 * @param string $className
348
	 * @param object $object
349
	 */
350 1
	public function onDisplayFkElementListDetails($element, $member, $className, $object) {
351 1
	}
352
353
	/**
354
	 * Returns a component for displaying a foreign object (from DataElement)
355
	 *
356
	 * @param string $memberFK
357
	 * @param mixed $objectFK
358
	 * @param string $fkClass
359
	 * @param string $fkTable
360
	 * @return string|NULL
361
	 */
362 2
	public function getFkMemberElement($memberFK, $objectFK, $fkClass, $fkTable) {
363 2
		$element = "";
364 2
		$_fkClass = str_replace ( "\\", ".", $fkClass );
365 2
		if (is_array ( $objectFK ) || $objectFK instanceof \Traversable) {
366 2
			$element = $this->getFkList ( $memberFK, $objectFK );
367 2
			foreach ( $objectFK as $oItem ) {
368 2
				if (method_exists ( $oItem, "__toString" )) {
369 2
					$id = (CRUDHelper::getIdentifierFunction ( $fkClass )) ( 0, $oItem );
370 2
					$item = $element->addItem ( $oItem . "" );
371 2
					$item->setProperty ( "data-ajax", $_fkClass . "||" . $id );
372 2
					$item->addClass ( "showTable" );
373 2
					$this->displayFkElementList ( $item, $memberFK, $fkClass, $oItem );
374
				}
375
			}
376
		} else {
377
			if (method_exists ( $objectFK, "__toString" )) {
378
				$id = (CRUDHelper::getIdentifierFunction ( $fkClass )) ( 0, $objectFK );
379
				$element = $this->getFkElement ( $memberFK, $fkClass, $objectFK );
380
				$element->setProperty ( "data-ajax", $_fkClass . "||" . $id )->addClass ( "showTable" );
381
			}
382
		}
383 2
		return $element;
384
	}
385
386
	/**
387
	 * Returns a list component for displaying a collection of foreign objects (*ToMany relations), (from DataElement)
388
	 *
389
	 * @param string $member
390
	 * @param string $className
391
	 * @param array|\Traversable $list
392
	 * @return \Ajax\common\html\HtmlCollection
393
	 */
394 2
	public function getFkList($member, $list) {
395 2
		$element = $this->jquery->semantic ()->htmlList ( "list-" . $member );
396 2
		$element->setMaxVisible ( 10 );
397 2
		return $element->addClass ( "animated" );
398
	}
399
400
	/**
401
	 * To modify for displaying an element in a list component of foreign objects, (from DataElement)
402
	 *
403
	 * @param \Ajax\common\html\HtmlDoubleElement $element
404
	 * @param string $member
405
	 * @param string $className
406
	 * @param object $object
407
	 */
408 2
	public function displayFkElementList($element, $member, $className, $object) {
409 2
	}
410
411
	/**
412
	 * Returns a component for displaying a single foreign object (manyToOne relation), (from DataElement)
413
	 *
414
	 * @param string $member
415
	 * @param string $className
416
	 * @param object $object
417
	 * @return \Ajax\common\html\BaseHtml
418
	 */
419
	public function getFkElement($member, $className, $object) {
420
		return $this->jquery->semantic ()->htmlLabel ( "element-" . $className . "." . $member, $object . "" );
421
	}
422
423
	/**
424
	 * To override to make sure that the detail of a clicked object is displayed or not
425
	 *
426
	 * @return boolean Return true if you want to see details
427
	 */
428 7
	public function showDetailsOnDataTableClick() {
429 7
		return true;
430
	}
431
}
432
433