Passed
Push — master ( bd3cb9...127ddb )
by Jean-Christophe
17:45
created

ModelViewer::addAllButtons()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 28
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 3.0473

Importance

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