Completed
Push — master ( f64d9c...5ef3c4 )
by Jean-Christophe
01:47
created

UbiquityMyAdminViewer::getControllersDataTable()   B

Complexity

Conditions 2
Paths 1

Size

Total Lines 37
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 37
rs 8.8571
c 0
b 0
f 0
cc 2
eloc 32
nc 1
nop 1
1
<?php
2
3
namespace micro\controllers\admin;
4
5
use Ajax\JsUtils;
6
use Ajax\semantic\widgets\dataform\DataForm;
7
use micro\orm\OrmUtils;
8
use Ajax\service\JArray;
9
use micro\orm\DAO;
10
use micro\orm\parser\Reflexion;
11
use Ajax\semantic\html\elements\HtmlHeader;
12
use Ajax\common\html\HtmlCollection;
13
use Ajax\common\html\BaseHtml;
14
use micro\cache\CacheManager;
15
use Ajax\semantic\html\elements\HtmlIcon;
16
use Ajax\semantic\html\base\constants\TextAlignment;
17
use micro\controllers\admin\popo\ControllerAction;
18
use Ajax\semantic\html\elements\HtmlLabel;
19
use Ajax\semantic\html\base\HtmlSemDoubleElement;
20
use Ajax\semantic\widgets\dataelement\DataElement;
21
use Ajax\semantic\html\elements\HtmlButton;
22
use Ajax\semantic\html\elements\html5\HtmlLink;
23
24
/**
25
 * @author jc
26
 *
27
 */
28
class UbiquityMyAdminViewer {
29
	/**
30
	 * @var JsUtils
31
	 */
32
	private $jquery;
33
34
	/**
35
	 * @var UbiquityMyAdminBaseController
36
	 */
37
	private $controller;
38
39
	public function __construct(UbiquityMyAdminBaseController $controller){
40
		$this->jquery=$controller->jquery;
41
		$this->controller=$controller;
42
	}
43
44
	/**
45
	 * Returns the form for adding or modifying an object
46
	 * @param string $identifier
47
	 * @param object $instance the object to add or modify
48
	 * @return DataForm
49
	 */
50
	public function getForm($identifier,$instance){
51
		$form=$this->jquery->semantic()->dataForm($identifier, $instance);
52
		$className=\get_class($instance);
53
		$fields=$this->controller->_getAdminData()->getFormFieldNames($className);
54
		$form->setFields($fields);
55
56
		$fieldTypes=OrmUtils::getFieldTypes($className);
57
		foreach ($fieldTypes as $property=>$type){
58
			switch ($type){
59
			case "boolean": case "bool":
60
				$form->fieldAsCheckbox($property);
61
				break;
62
			case "int": case "integer":
63
				$form->fieldAsInput($property,["inputType"=>"number"]);
64
				break;
65
			}
66
		}
67
		$this->relationMembersInForm($form, $instance, $className);
68
		$form->setCaptions($this->getFormCaptions($form->getInstanceViewer()->getVisibleProperties(),$className,$instance));
69
		$form->setSubmitParams($this->controller->_getAdminFiles()->getAdminBaseRoute()."/update", "#table-details");
70
		return $form;
71
	}
72
73
	/**
74
	 * Condition to determine if the edit or add form is modal for $model objects
75
	 * @param array $objects
76
	 * @param string $model
77
	 * @return boolean
78
	 */
79
	public function isModal($objects,$model){
80
		return \count($objects)>20;
81
	}
82
83
	/**
84
	 * Returns the captions for list fields in showTable action
85
	 * @param array $captions
86
	 * @param string $className
87
	 */
88
	public function getCaptions($captions,$className){
89
		return array_map("ucfirst", $captions);
90
	}
91
92
	/**
93
	 * Returns the captions for form fields
94
	 * @param array $captions
95
	 * @param string $className
96
	 */
97
	public function getFormCaptions($captions,$className,$instance){
98
		return array_map("ucfirst", $captions);
99
	}
100
101
	public function getFkHeaderElement($member,$className,$object){
102
		return new HtmlHeader("",4,$member,"content");
103
	}
104
105
	public function getFkHeaderList($member,$className,$list){
106
		return new HtmlHeader("",4,$member." (".\count($list).")","content");
107
	}
108
109
	/**
110
	 * @param string $member
111
	 * @param string $className
112
	 * @param object $object
113
	 * @return BaseHtml
114
	 */
115
	public function getFkElement($member,$className,$object){
116
		return $this->jquery->semantic()->htmlLabel("element-".$className.".".$member,$object."");
117
	}
118
119
	/**
120
	 * @param string $member
121
	 * @param string $className
122
	 * @param array|\Traversable $list
123
	 * @return HtmlCollection
124
	 */
125
	public function getFkList($member,$className,$list){
126
		$element=$this->jquery->semantic()->htmlList("list-".$className.".".$member);
127
		return $element->addClass("animated divided celled");
128
	}
129
130
	public function displayFkElementList($element,$member,$className,$object){
131
132
	}
133
134
	public function getMainMenuElements(){
135
		return ["models"=>["Models","sticky note","Used to perform CRUD operations on data."],
136
				"routes"=>["Routes","car","Displays defined routes with annotations"],
137
				"controllers"=>["Controllers","heartbeat","Displays controllers and actions"],
138
				"cache"=>["Cache","lightning","Annotations, models, router and controller cache"],
139
				"config"=>["Config","settings","Configuration variables"]
140
		];
141
	}
142
143
	public function getRoutesDataTable($routes){
144
		$dt=$this->jquery->semantic()->dataTable("dtRoutes", "micro\controllers\admin\popo\Route", $routes);
145
		$dt->setFields(["path","methods","controller","action","parameters","cache","duration","name","expired"]);
146
		$dt->setCaptions(["Path","Methods","Controller","Action","Parameters","Cache","Duration","Name","Expired",""]);
147
		$dt->fieldAsLabel("path","car");
148
		$dt->fieldAsCheckbox("cache",["disabled"=>"disabled"]);
149
		$dt->setValueFunction("methods", function($v){return (\is_array($v))?"[".\implode(", ", $v)."]":$v;});
150
		$dt->setValueFunction("parameters", function($v){return (\is_array($v))?"[".\implode(", ", $v)."]":$v;});
151
		$dt->setValueFunction("expired", function($v,$instance,$index){
152
			$icon=null;$expired=null;
153
			if($instance->getCache()){
154
				if(\sizeof($instance->getParameters())===0 || $instance->getParameters()===null)
155
					$expired=CacheManager::isExpired($instance->getPath(),$instance->getDuration());
156
					if($expired===false){
157
						$icon=new HtmlIcon("", "toggle on");
158
					}elseif($expired===true){
159
						$icon=new HtmlIcon("", "toggle off");
160
					}else{
161
						$icon=new HtmlIcon("", "help");
162
					}
163
			}
164
165
			return $icon;
166
		});
167
		$dt->onRowClick('$("#filter-routes").val($(this).find(".ui.label").text());');
168
		$dt->onPreCompile(function($dTable){
169
			$dTable->setColAlignment(6, TextAlignment::RIGHT);
170
			$dTable->setColAlignment(8, TextAlignment::CENTER);
171
		});
172
		$dt->addFieldButton("Get",true,function(&$bt,$instance){$bt->addClass("_get")->setProperty("data-url",$instance->getPath());});
173
		$dt->insertInFieldButton(9,"Post",true,function(&$bt,$instance){$bt->addClass("_post")->setProperty("data-url",$instance->getPath());});
174
		$dt->setActiveRowSelector("warning");
175
		return $dt;
176
	}
177
178
	public function getControllersDataTable($controllers){
179
		$dt=$this->jquery->semantic()->dataTable("dtControllers", "micro\controllers\admin\popo\ControllerAction", $controllers);
180
		$dt->setFields(["controller","action","dValues"]);
181
		$dt->setIdentifierFunction(function($i,$instance){return \urlencode($instance->getController());});
182
		$dt->setCaptions(["Controller","Action [routes]","Default values",""]);
183
		$dt->setValueFunction("controller", function($v,$instance,$index){
184
			$bt=new HtmlButton("bt-".\urlencode($v),$v);
185
			$bt->setSize("large");
186
			$bt->addIcon("heartbeat",true,true);
187
			$bt->setToggle();
188
			$bt->onClick("$(\"tr[data-ajax='".\urlencode($instance->getController())."'] td:not([rowspan])\").toggle(!$(this).hasClass('active'));");
189
			return $bt;
190
		});
191
		$dt->setValueFunction("action", function($v,$instance,$index){
192
			$params=$instance->getParameters();
193
			\array_walk($params, function(&$item){ $item= $item->name;});
194
			$params= " (".\implode(" , ", $params).")";
195
			$v=new HtmlSemDoubleElement("","span","","<b>".$v."</b>");
196
			$v->setProperty("style", "color: #3B83C0;");
197
			$v->addIcon("lightning");
198
			$v.=new HtmlSemDoubleElement("","span","",$params);
199
			$annots=$instance->getAnnots();
200
			foreach ($annots as $path=>$annotDetail){
201
				$lbl=new HtmlLabel("",$path,"car");
202
				$lbl->setProperty("data-ajax", \htmlspecialchars(($path)));
203
				$lbl->addClass("_route");
204
				$v.="&nbsp;".$lbl;
205
			}
206
			return $v;
207
		});
208
		$dt->onPreCompile(function($dt){
209
			$dt->getHtmlComponent()->mergeIdentiqualValues(0);
210
		});
211
		$dt->setEdition(true);
212
		$dt->addClass("compact");
213
		$dt->addFieldButton("Get",true,function(&$bt,$instance){$bt->addClass("_get")->setProperty("data-url",$instance->getPath());});
214
		$dt->insertInFieldButton(3,"Post",true,function(&$bt,$instance){$bt->addClass("_post")->setProperty("data-url",$instance->getPath());});
215
		return $dt;
216
	}
217
218
	public function getCacheDataTable($cacheFiles){
219
		$dt=$this->jquery->semantic()->dataTable("dtCacheFiles", "micro\controllers\admin\popo\CacheFile", $cacheFiles);
220
		$dt->setFields(["type","name","timestamp","size"]);
221
		$dt->setCaptions(["Type","Name","Timestamp","Size",""]);
222
		$dt->setValueFunction("type", function($v,$instance,$index){
223
			$item=$this->jquery->semantic()->htmlDropdown("dd-type-".$v,$v);
224
			$item->addItems(["Delete all","(Re-)Init cache"]);
225
			$item->setPropertyValues("data-ajax", $v);
226
			$item->getItem(0)->addClass("_delete-all");
227
			if($instance->getFile()==="")
228
				$item->getItem(0)->setDisabled();
229
			$item->getItem(1)->addClass("_init");
230
			if($instance->getType()!=="Models" && $instance->getType()!=="Controllers")
231
				$item->getItem(1)->setDisabled();
232
			$item->asButton()->addIcon("folder",true,true);
233
			return $item;
234
		});
235
		$dt->addDeleteButton(true,[],function($o,$instance){if($instance->getFile()=="")$o->setDisabled();});
236
		$dt->setIdentifierFunction("getFile");
237
		$dt->setValueFunction("timestamp", function($v){
238
			if($v!=="")
239
				return date(DATE_RFC2822,$v);
240
		});
241
		$dt->setValueFunction("size", function($v){
242
			if($v!=="")
243
			return self::formatBytes($v);
244
		});
245
		$dt->setValueFunction("name", function($name,$instance,$i){
246
			$link=new HtmlLink("lnl-".$i);
247
			$link->setContent($name);
248
			$link->addIcon("edit");
249
			$link->addClass("_lnk");
250
			$link->setProperty("data-type", $instance->getType());
251
			$link->setProperty("data-ajax", $instance->getFile());
252
			return $link;
253
		});
254
		$dt->onPreCompile(function($dt){
255
			$dt->getHtmlComponent()->mergeIdentiqualValues(0);
256
		});
257
		$this->jquery->postOnClick("._lnk", $this->controller->_getAdminFiles()->getAdminBaseRoute()."/_showFileContent","{type:$(this).attr('data-type'),filename:$(this).attr('data-ajax')}","#modal");
258
		$this->jquery->postFormOnClick("._delete", $this->controller->_getAdminFiles()->getAdminBaseRoute()."/deleteCacheFile", "frmCache","#dtCacheFiles tbody",["jqueryDone"=>"replaceWith","params"=>"{toDelete:$(this).attr('data-ajax')}"]);
259
		$this->jquery->postFormOnClick("._delete-all", $this->controller->_getAdminFiles()->getAdminBaseRoute()."/deleteAllCacheFiles", "frmCache","#dtCacheFiles tbody",["jqueryDone"=>"replaceWith","params"=>"{type:$(this).attr('data-ajax')}"]);
260
		$this->jquery->postFormOnClick("._init", $this->controller->_getAdminFiles()->getAdminBaseRoute()."/initCacheType", "frmCache","#dtCacheFiles tbody",["jqueryDone"=>"replaceWith","params"=>"{type:$(this).attr('data-ajax')}"]);
261
		return $dt;
262
	}
263
264
	public function getModelsStructureDataTable($datas){
265
		$de=$this->jquery->semantic()->dataElement("dtStructure", $datas);
266
		$fields=\array_keys($datas);
267
		$de->setFields($fields);
268
		$de->setCaptions($fields);
269
		foreach ($fields as $key){
270
			$de->setValueFunction($key, function($value) use ($key){
271
				if($value instanceof  \stdClass){
272
					$value=(array) $value;
273
				}
274
				return \print_r($value,true);
275
			});
276
		}
277
		return $de;
278
	}
279
280
	public function getConfigDataElement($config){
281
		$de=$this->jquery->semantic()->dataElement("deConfig", $config);
282
		$fields=\array_keys($config);
283
		$de->setFields($fields);
284
		$de->setCaptions($fields);
285
		$de->setValueFunction("database", function($v,$instance,$index){
286
			$dbDe=new DataElement("",$v);
287
			$dbDe->setFields(["dbName","serverName","port","user","password","cache"]);
288
			$dbDe->setCaptions(["dbName","serverName","port","user","password","cache"]);
289
			return $dbDe;
290
		});
291
		$de->setValueFunction("templateEngineOptions", function($v,$instance,$index){
292
			$teoDe=new DataElement("",$v);
293
			$teoDe->setFields(["cache"]);
294
			$teoDe->setCaptions(["cache"]);
295
			$teoDe->fieldAsCheckbox("cache",["class"=>"ui checkbox slider"]);
296
			return $teoDe;
297
		});
298
		$de->setValueFunction("mvcNS", function($v,$instance,$index){
299
			$mvcDe=new DataElement("",$v);
300
			$mvcDe->setFields(["models","controllers"]);
301
			$mvcDe->setCaptions(["Models","Controllers"]);
302
			return $mvcDe;
303
		});
304
		$de->setValueFunction("di", function($v,$instance,$index) use($config){
305
			$diDe=new DataElement("",$v);
306
			$keys=\array_keys($config["di"]);
307
			$diDe->setFields($keys);
308
			foreach ($keys as $key){
309
				$diDe->setValueFunction($key, function($value) use ($config,$key){
310
					$r =$config['di'][$key];
311
					return \nl2br(self::closure_dump($r));
312
313
				});
314
			}
315
			return $diDe;
316
		});
317
		$de->fieldAsCheckbox("test",["class"=>"ui checkbox slider"]);
318
		$de->fieldAsCheckbox("debug",["class"=>"ui checkbox slider"]);
319
		return $de;
320
	}
321
322
	private static function closure_dump(\Closure $c) {
323
		$str = 'function (';
324
		$r = new \ReflectionFunction($c);
325
		$params = array();
326
		foreach($r->getParameters() as $p) {
327
			$s = '';
328
			if($p->isArray()) {
329
				$s .= 'array ';
330
			} else if($p->getClass()) {
331
				$s .= $p->getClass()->name . ' ';
332
			}
333
			if($p->isPassedByReference()){
334
				$s .= '&';
335
			}
336
			$s .= '$' . $p->name;
337
			if($p->isOptional()) {
338
				$s .= ' = ' . \var_export($p->getDefaultValue(), TRUE);
339
			}
340
			$params []= $s;
341
		}
342
		$str .= \implode(', ', $params);
343
		$str .= '){' . PHP_EOL;
344
		$lines = file($r->getFileName());
345
		for($l = $r->getStartLine(); $l < $r->getEndLine(); $l++) {
346
			$str .= $lines[$l];
347
		}
348
		return $str;
349
	}
350
351
	private static function formatBytes($size, $precision = 2){
352
		$base = log($size, 1024);
353
		$suffixes = array('o', 'Ko', 'Mo', 'Go', 'To');
354
		return round(pow(1024, $base - floor($base)), $precision) .' '. $suffixes[floor($base)];
355
	}
356
357
	protected function relationMembersInForm($form,$instance,$className){
358
		$relations = OrmUtils::getFieldsInRelations($className);
359
		foreach ($relations as $member){
360
			if($this->controller->_getAdminData()->getUpdateManyToOneInForm() && OrmUtils::getAnnotationInfoMember($className, "#manyToOne",$member)!==false){
361
				$this->manyToOneFormField($form, $member, $className, $instance);
362
			}elseif($this->controller->_getAdminData()->getUpdateOneToManyInForm() && ($annot=OrmUtils::getAnnotationInfoMember($className, "#oneToMany",$member))!==false){
363
				$this->oneToManyFormField($form, $member, $instance,$annot);
364
			}elseif($this->controller->_getAdminData()->getUpdateManyToManyInForm() && ($annot=OrmUtils::getAnnotationInfoMember($className, "#manyToMany",$member))!==false){
365
				$this->manyToManyFormField($form, $member, $instance,$annot);
366
			}
367
		}
368
	}
369
370
	protected function manyToOneFormField(DataForm $form,$member,$className,$instance){
371
		$joinColumn=OrmUtils::getAnnotationInfoMember($className, "#joinColumn", $member);
372
		if($joinColumn){
373
			$fkObject=Reflexion::getMemberValue($instance, $member);
374
			$fkClass=$joinColumn["className"];
375
			if($fkObject===null){
376
				$fkObject=new $fkClass();
377
			}
378
			$fkId=OrmUtils::getFirstKey($fkClass);
379
			$fkIdGetter="get".\ucfirst($fkId);
380
			if(\method_exists($fkObject, "__toString") && \method_exists($fkObject, $fkIdGetter)){
381
				$fkField=$joinColumn["name"];
382
				$fkValue=OrmUtils::getFirstKeyValue($fkObject);
383
				if(!Reflexion::setMemberValue($instance, $fkField, $fkValue)){
384
					$instance->{$fkField}=OrmUtils::getFirstKeyValue($fkObject);
385
					$form->addField($fkField);
386
				}
387
				$form->fieldAsDropDown($fkField,JArray::modelArray(DAO::getAll($fkClass),$fkIdGetter,"__toString"));
388
				$form->setCaption($fkField, \ucfirst($member));
389
			}
390
		}
391
	}
392
	protected function oneToManyFormField(DataForm $form,$member,$instance,$annot){
393
		$newField=$member."Ids";
394
		$fkClass=$annot["className"];
395
		$fkId=OrmUtils::getFirstKey($fkClass);
396
		$fkIdGetter="get".\ucfirst($fkId);
397
		$fkInstances=DAO::getOneToMany($instance, $member);
398
		$form->addField($newField);
399
		$ids=\array_map(function($elm) use($fkIdGetter){return $elm->{$fkIdGetter}();},$fkInstances);
400
		$instance->{$newField}=\implode(",", $ids);
401
		$form->fieldAsDropDown($newField,JArray::modelArray(DAO::getAll($fkClass),$fkIdGetter,"__toString"),true);
402
		$form->setCaption($newField, \ucfirst($member));
403
	}
404
405
	protected function manyToManyFormField(DataForm $form,$member,$instance,$annot){
406
		$newField=$member."Ids";
407
		$fkClass=$annot["targetEntity"];
408
		$fkId=OrmUtils::getFirstKey($fkClass);
409
		$fkIdGetter="get".\ucfirst($fkId);
410
		$fkInstances=DAO::getManyToMany($instance, $member);
411
		$form->addField($newField);
412
		$ids=\array_map(function($elm) use($fkIdGetter){return $elm->{$fkIdGetter}();},$fkInstances);
413
		$instance->{$newField}=\implode(",", $ids);
414
		$form->fieldAsDropDown($newField,JArray::modelArray($this->controller->_getAdminData()->getManyToManyDatas($fkClass, $instance, $member),$fkIdGetter,"__toString"),true,["jsCallback"=>function($elm){$elm->getField()->asSearch();}]);
415
		$form->setCaption($newField, \ucfirst($member));
416
	}
417
}
418