ModelViewer::onDataTableRowButton()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 1
Code Lines 0

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 0
c 0
b 0
f 0
dl 0
loc 1
ccs 1
cts 1
cp 1
rs 10
cc 1
nc 1
nop 2
crap 1
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): \Ajax\semantic\widgets\dataelement\DataElement {
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 2
		} );
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 2
					} );
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): array {
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): DataTable {
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 2
			} );
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
		}
176 5
		return;
177
	}
178
	
179
	/**
180
	 * Returns the fields on which a grouping is performed
181
	 */
182 5
	public function getGroupByFields() {
183 5
		return;
184
	}
185
	
186
	/**
187
	 * Returns the dataTable instance for dispaying a list of object
188
	 *
189
	 * @param array $instances
190
	 * @param string $model
191
	 * @param number $totalCount
192
	 * @param number $page
193
	 * @return DataTable
194
	 */
195 8
	protected function getDataTableInstance($instances, $model, $totalCount, $page = 1): DataTable {
196 8
		$dtId = $this->getDataTableId ();
197 8
		$semantic = $this->jquery->semantic ();
198 8
		$recordsPerPage = $this->recordsPerPage ( $model, $totalCount );
199 8
		if (\is_numeric ( $recordsPerPage )) {
200 4
			$grpByFields = $this->getGroupByFields ();
201 4
			if (\is_array ( $grpByFields )) {
202
				$dataTable = $semantic->dataTable ( $dtId, $model, $instances );
203
				$dataTable->setGroupByFields ( $grpByFields );
204
			} else {
205 4
				$dataTable = $semantic->jsonDataTable ( $dtId, $model, $instances );
206
			}
207 4
			$dataTable->paginate ( $page, $totalCount, $recordsPerPage, 5 );
208 4
			$dataTable->onSearchTerminate ( '$("#search-query-content").html(data);$("#search-query").show();$("#table-details").html("");' );
209
		} else {
210 5
			$dataTable = $semantic->dataTable ( $dtId, $model, $instances );
211
		}
212 8
		$dataTable->setLibraryId ( 'lv' );
213 8
		return $dataTable;
214
	}
215
	
216
	/**
217
	 * Returns an array of buttons ["display","edit","delete"] to display for each row in dataTable
218
	 *
219
	 * @return string[]
220
	 */
221 4
	protected function getDataTableRowButtons(): array {
222 4
		return [ 'edit','delete' ];
223
	}
224
	
225 8
	public function addAllButtons(DataTable $dataTable, $attributes) {
226 8
		$transition = $this->getTransition ();
227 8
		$dataTable->onPreCompile ( function () use (&$dataTable) {
228 8
			$dataTable->getHtmlComponent ()->colRightFromRight ( 0 );
229 8
			$tb = $dataTable->getPaginationToolbar ();
230 8
			if (isset ( $tb )) {
231 4
				$tb->addClass ( $this->style );
232
			}
233 8
		} );
234 8
			$dataTable->addAllButtons ( false, [ 'ajaxTransition' => $transition,'hasLoader' => 'internal' ], function ($bt) {
235 5
				$bt->addClass ( 'circular ' . $this->style );
236 5
				$this->onDataTableRowButton ( $bt ,'display');
237 8
			}, function ($bt) {
238 8
				$bt->addClass ( 'circular ' . $this->style );
239 8
				$this->onDataTableRowButton ( $bt ,'edit');
240 8
			}, function ($bt) {
241 8
				$bt->addClass ( 'circular ' . $this->style );
242 8
				$this->onDataTableRowButton ( $bt ,'delete');
243 8
			} );
244 8
				$buttons=\array_diff($this->getDataTableRowButtons(),['edit','display','delete']);
245 8
				foreach ($buttons as $bt){
246
					$attr=JString::cleanIdentifier($bt);
247
					$dataTable->insertDefaultButtonIn($dataTable->getButtonsColumn(),$bt,"_$attr circular basic",false,function($b) use($attr){
248
						$b->addClass ( $this->style );
249
						$this->onDataTableRowButton ( $b,$attr );
250
					},$bt);
251
				}
252 8
				$dataTable->setDisplayBehavior ( [ 'jsCallback' => '$("#dataTable").hide();','ajaxTransition' => $transition,'hasLoader' => 'internal' ] );
253
	}
254
	
255
	/**
256
	 * The default transition for display, edit and delete behaviors
257
	 *
258
	 * @return string
259
	 */
260 8
	public function getTransition(): string {
261 8
		return 'fade';
262
	}
263
	
264 8
	public function getDataTableId(): string {
265 8
		return 'lv';
266
	}
267
	
268
	/**
269
	 * To override for modifying the dataTable row buttons
270
	 *
271
	 * @param HtmlButton $bt
272
	 * @param ?string $name
273
	 */
274 8
	public function onDataTableRowButton(HtmlButton $bt,?string $name=null) {
275 8
	}
276
	
277
	/**
278
	 * To override for modifying the showConfMessage dialog buttons
279
	 *
280
	 * @param HtmlButton $confirmBtn The confirmation button
281
	 * @param HtmlButton $cancelBtn The cancellation button
282
	 */
283 3
	public function onConfirmButtons(HtmlButton $confirmBtn, HtmlButton $cancelBtn) {
284 3
	}
285
	
286
	/**
287
	 * Returns the captions for list fields in showTable action
288
	 *
289
	 * @param array $captions
290
	 * @param string $className
291
	 */
292 8
	public function getCaptions($captions, $className):array {
293 8
		return \array_map ( 'ucfirst', $captions );
294
	}
295
	
296
	/**
297
	 * Returns the header for a single foreign object (element is an instance, issue from ManyToOne), (from DataTable)
298
	 *
299
	 * @param string $member
300
	 * @param string $className
301
	 * @param object $object
302
	 * @return HtmlHeader
303
	 */
304 1
	public function getFkHeaderElementDetails($member, $className, $object) {
305 1
		$res = new HtmlHeader ( '', 4, $member, 'content' );
306 1
		return $res->addClass ( $this->style );
307
	}
308
	
309
	/**
310
	 * Returns the header for a list of foreign objects (issue from oneToMany or ManyToMany), (from DataTable)
311
	 *
312
	 * @param string $member
313
	 * @param string $className
314
	 * @param array $list
315
	 * @return HtmlHeader
316
	 */
317 2
	public function getFkHeaderListDetails($member, $className, $list) {
318 2
		$res = new HtmlHeader ( '', 4, $member . ' (' . \count ( $list ) . ')', 'content' );
319 2
		return $res->addClass ( $this->style );
320
	}
321
	
322
	/**
323
	 * Returns a component for displaying a single foreign object (manyToOne relation), (from DataTable)
324
	 *
325
	 * @param string $member
326
	 * @param string $className
327
	 * @param object $object
328
	 * @return \Ajax\common\html\BaseHtml
329
	 */
330 1
	public function getFkElementDetails($member, $className, $object) {
331 1
		$res = $this->jquery->semantic ()->htmlLabel ( 'element-' . $className . '.' . $member, $object . '' );
332 1
		return $res->addClass ( $this->style );
333
	}
334
	
335
	/**
336
	 * Returns a list component for displaying a collection of foreign objects (*ToMany relations), (from DataTable)
337
	 *
338
	 * @param string $member
339
	 * @param string $className
340
	 * @param array|\Traversable $list
341
	 * @return \Ajax\common\html\HtmlCollection
342
	 */
343 2
	public function getFkListDetails($member, $className, $list) {
344 2
		$element = $this->jquery->semantic ()->htmlList ( 'list-' . $className . '.' . $member );
345 2
		$element->setMaxVisible ( 15 );
346
		
347 2
		return $element->addClass ( 'animated divided celled ' . $this->style );
348
	}
349
	
350
	/**
351
	 * Returns a component for displaying a foreign object (from DataTable)
352
	 *
353
	 * @param string $memberFK
354
	 * @param mixed $objectFK
355
	 * @param string $fkClass
356
	 * @param string $fkTable
357
	 * @return \Ajax\semantic\html\elements\HtmlHeader[]|\Ajax\common\html\BaseHtml[]|NULL
358
	 */
359 2
	public function getFkMemberElementDetails($memberFK, $objectFK, $fkClass, $fkTable) {
360 2
		$_fkClass = str_replace ( "\\", ".", $fkClass );
361 2
		$header = new HtmlHeader ( "", 4, $memberFK, "content" );
362 2
		if (is_array ( $objectFK ) || $objectFK instanceof \Traversable) {
363 2
			$header = $this->getFkHeaderListDetails ( $memberFK, $fkClass, $objectFK );
364 2
			$element = $this->getFkListDetails ( $memberFK, $fkClass, $objectFK );
365 2
			foreach ( $objectFK as $oItem ) {
366 2
				if (method_exists ( $oItem, "__toString" )) {
367 2
					$id = (CRUDHelper::getIdentifierFunction ( $fkClass )) ( 0, $oItem );
368 2
					$item = $element->addItem ( $oItem . "" );
369 2
					$item->setProperty ( "data-ajax", $_fkClass . "||" . $id );
370 2
					$item->addClass ( "showTable" );
371 2
					$this->onDisplayFkElementListDetails ( $item, $memberFK, $fkClass, $oItem );
372
				}
373
			}
374
		} else {
375 1
			if (method_exists ( $objectFK, "__toString" )) {
376 1
				$header = $this->getFkHeaderElementDetails ( $memberFK, $fkClass, $objectFK );
377 1
				$id = (CRUDHelper::getIdentifierFunction ( $fkClass )) ( 0, $objectFK );
378 1
				$element = $this->getFkElementDetails ( $memberFK, $fkClass, $objectFK );
379 1
				$element->setProperty ( "data-ajax", $_fkClass . "||" . $id )->addClass ( "showTable" );
380
			}
381
		}
382 2
		if (isset ( $element )) {
383 2
			return [ $header,$element ];
384
		}
385
		return null;
386
	}
387
	
388
	/**
389
	 * To modify for displaying an element in a list component of foreign objects (from DataTable)
390
	 *
391
	 * @param \Ajax\common\html\HtmlDoubleElement $element
392
	 * @param string $member
393
	 * @param string $className
394
	 * @param object $object
395
	 */
396 2
	public function onDisplayFkElementListDetails($element, $member, $className, $object) {
397 2
	}
398
	
399
	/**
400
	 * Returns a component for displaying a foreign object (from DataElement)
401
	 *
402
	 * @param string $memberFK
403
	 * @param mixed $objectFK
404
	 * @param string $fkClass
405
	 * @param string $fkTable
406
	 * @return string|NULL
407
	 */
408 2
	public function getFkMemberElement($memberFK, $objectFK, $fkClass, $fkTable) {
409 2
		$element = "";
410 2
		$_fkClass = str_replace ( "\\", ".", $fkClass );
411 2
		if (is_array ( $objectFK ) || $objectFK instanceof \Traversable) {
412 2
			$element = $this->getFkList ( $memberFK, $objectFK );
413 2
			foreach ( $objectFK as $oItem ) {
414 2
				if (\method_exists ( $oItem, '__toString' )) {
415 2
					$id = (CRUDHelper::getIdentifierFunction ( $fkClass )) ( 0, $oItem );
416 2
					$item = $element->addItem ( $oItem . '' );
417 2
					$item->setProperty ( 'data-ajax', $_fkClass . '||' . $id );
418 2
					$item->addClass ( 'showTable' );
419 2
					$this->displayFkElementList ( $item, $memberFK, $fkClass, $oItem );
420
				}
421
			}
422
		} else {
423
			if (method_exists ( $objectFK, '__toString' )) {
424
				$id = (CRUDHelper::getIdentifierFunction ( $fkClass )) ( 0, $objectFK );
425
				$element = $this->getFkElement ( $memberFK, $fkClass, $objectFK );
426
				$element->setProperty ( 'data-ajax', $_fkClass . '||' . $id )->addClass ( 'showTable' );
427
			}
428
		}
429 2
		return $element;
430
	}
431
	
432
	/**
433
	 * Returns a list component for displaying a collection of foreign objects (*ToMany relations), (from DataElement)
434
	 *
435
	 * @param string $member
436
	 * @param string $className
437
	 * @param array|\Traversable $list
438
	 * @return \Ajax\common\html\HtmlCollection
439
	 */
440 2
	public function getFkList($member, $list) {
441 2
		$element = $this->jquery->semantic ()->htmlList ( 'list-' . $member );
442 2
		$element->setMaxVisible ( 10 );
443 2
		return $element->addClass ( 'animated' );
444
	}
445
	
446
	/**
447
	 * To modify for displaying an element in a list component of foreign objects, (from DataElement)
448
	 *
449
	 * @param \Ajax\common\html\HtmlDoubleElement $element
450
	 * @param string $member
451
	 * @param string $className
452
	 * @param object $object
453
	 */
454 2
	public function displayFkElementList($element, $member, $className, $object) {
455 2
	}
456
	
457
	/**
458
	 * Returns a component for displaying a single foreign object (manyToOne relation), (from DataElement)
459
	 *
460
	 * @param string $member
461
	 * @param string $className
462
	 * @param object $object
463
	 * @return \Ajax\common\html\BaseHtml
464
	 */
465
	public function getFkElement($member, $className, $object) {
466
		$res = $this->jquery->semantic ()->htmlLabel ( 'element-' . $className . '.' . $member, $object . '' );
467
		return $res->addClass ( $this->style );
468
	}
469
	
470
	/**
471
	 * To override to make sure that the detail of a clicked object is displayed or not
472
	 *
473
	 * @return boolean Return true if you want to see details
474
	 */
475 8
	public function showDetailsOnDataTableClick(): bool {
476 8
		return true;
477
	}
478
}
479
480