Completed
Push — master ( 980c15...74d9cb )
by Jean-Christophe
01:25
created

UbiquityMyAdminViewer::oneToManyFormField()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 12
rs 9.4285
cc 1
eloc 11
nc 1
nop 4
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
23
/**
24
 * @author jc
25
 *
26
 */
27
class UbiquityMyAdminViewer {
28
	/**
29
	 * @var JsUtils
30
	 */
31
	private $jquery;
32
33
	/**
34
	 * @var UbiquityMyAdminBaseController
35
	 */
36
	private $controller;
37
38
	public function __construct(UbiquityMyAdminBaseController $controller){
39
		$this->jquery=$controller->jquery;
40
		$this->controller=$controller;
41
	}
42
43
	/**
44
	 * Returns the form for adding or modifying an object
45
	 * @param string $identifier
46
	 * @param object $instance the object to add or modify
47
	 * @return DataForm
48
	 */
49
	public function getForm($identifier,$instance){
50
		$form=$this->jquery->semantic()->dataForm($identifier, $instance);
51
		$className=\get_class($instance);
52
		$fields=$this->controller->_getAdminData()->getFormFieldNames($className);
53
		$form->setFields($fields);
54
55
		$fieldTypes=OrmUtils::getFieldTypes($className);
56
		foreach ($fieldTypes as $property=>$type){
57
			switch ($type){
58
				case "boolean": case "bool":
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
59
					$form->fieldAsCheckbox($property);
60
					break;
61
				case "int": case "integer":
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
62
					$form->fieldAsInput($property,["inputType"=>"number"]);
63
					break;
64
			}
65
		}
66
		$this->relationMembersInForm($form, $instance, $className);
67
		$form->setCaptions($this->getFormCaptions($form->getInstanceViewer()->getVisibleProperties(),$className,$instance));
68
		$form->setSubmitParams($this->controller->_getAdminFiles()->getAdminBaseRoute()."/update", "#table-details");
69
		return $form;
70
	}
71
72
	/**
73
	 * Condition to determine if the edit or add form is modal for $model objects
74
	 * @param array $objects
75
	 * @param string $model
76
	 * @return boolean
77
	 */
78
	public function isModal($objects,$model){
79
		return \count($objects)>20;
80
	}
81
82
	/**
83
	 * Returns the captions for list fields in showTable action
84
	 * @param array $captions
85
	 * @param string $className
86
	 */
87
	public function getCaptions($captions,$className){
1 ignored issue
show
Unused Code introduced by
The parameter $className is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
88
		return array_map("ucfirst", $captions);
89
	}
90
91
	/**
92
	 * Returns the captions for form fields
93
	 * @param array $captions
94
	 * @param string $className
95
	 */
96
	public function getFormCaptions($captions,$className,$instance){
1 ignored issue
show
Unused Code introduced by
The parameter $className is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $instance is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
97
		return array_map("ucfirst", $captions);
98
	}
99
100
	public function getFkHeaderElement($member,$className,$object){
2 ignored issues
show
Unused Code introduced by
The parameter $className is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $object is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
101
		return new HtmlHeader("",4,$member,"content");
102
	}
103
104
	public function getFkHeaderList($member,$className,$list){
1 ignored issue
show
Unused Code introduced by
The parameter $className is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
105
		return new HtmlHeader("",4,$member." (".\count($list).")","content");
106
	}
107
108
	/**
109
	 * @param string $member
110
	 * @param string $className
111
	 * @param object $object
112
	 * @return BaseHtml
113
	 */
114
	public function getFkElement($member,$className,$object){
115
		return $this->jquery->semantic()->htmlLabel("element-".$className.".".$member,$object."");
116
	}
117
118
	/**
119
	 * @param string $member
120
	 * @param string $className
121
	 * @param array|\Traversable $list
122
	 * @return HtmlCollection
123
	 */
124
	public function getFkList($member,$className,$list){
1 ignored issue
show
Unused Code introduced by
The parameter $list is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
125
		$element=$this->jquery->semantic()->htmlList("list-".$className.".".$member);
126
		return $element->addClass("animated divided celled");
127
	}
128
129
	public function displayFkElementList($element,$member,$className,$object){
0 ignored issues
show
Unused Code introduced by
The parameter $element is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $member is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $className is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $object is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
130
131
	}
132
133
	public function getMainMenuElements(){
134
		return ["models"=>["Models","sticky note","Used to perform CRUD operations on data."],
135
				"routes"=>["Routes","car","Displays defined routes with annotations"],
136
				"controllers"=>["Controllers","heartbeat","Displays controllers and actions"],
137
				"cache"=>["Cache","lightning","Annotations, models, router and controller cache"],
138
				"config"=>["Config","settings","Configuration variables"]
139
		];
140
	}
141
142
	public function getRoutesDataTable($routes){
143
		$dt=$this->jquery->semantic()->dataTable("dtRoutes", "micro\controllers\admin\popo\Route", $routes);
144
		$dt->setFields(["path","methods","controller","action","parameters","cache","duration","name","expired"]);
145
		$dt->setCaptions(["Path","Methods","Controller","Action","Parameters","Cache","Duration","Name","Expired"]);
146
		$dt->fieldAsLabel("path","car");
147
		$dt->fieldAsCheckbox("cache",["disabled"=>"disabled"]);
148
		$dt->setValueFunction("methods", function($v){return (\is_array($v))?"[".\implode(", ", $v)."]":$v;});
149
		$dt->setValueFunction("parameters", function($v){return (\is_array($v))?"[".\implode(", ", $v)."]":$v;});
150
		$dt->setValueFunction("expired", function($v,$instance,$index){
0 ignored issues
show
Unused Code introduced by
The parameter $index is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
151
			$icon=null;$expired=null;
152
			if($instance->getCache()){
153
				if(\sizeof($instance->getParameters())===0 || $instance->getParameters()===null)
154
					$expired=CacheManager::isExpired($instance->getPath(),$instance->getDuration());
0 ignored issues
show
Bug introduced by
The method isExpired() does not exist on micro\cache\CacheManager. Did you maybe mean expired()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
155
					if($expired===false){
156
						$icon=new HtmlIcon("", "toggle on");
157
					}elseif($expired===true){
158
						$icon=new HtmlIcon("", "toggle off");
159
					}else{
160
						$icon=new HtmlIcon("", "help");
161
					}
162
			}
163
164
			return $icon;
165
		});
166
		$dt->onRowClick('$("#filter-routes").val($(this).find(".ui.label").text());');
167
		$dt->onPreCompile(function($dTable){
168
			$dTable->setColAlignment(6, TextAlignment::RIGHT);
169
			$dTable->setColAlignment(8, TextAlignment::CENTER);
170
		});
171
		$dt->setActiveRowSelector("warning");
172
		return $dt;
173
	}
174
175
	public function getControllersDataTable($controllers){
176
		$dt=$this->jquery->semantic()->dataTable("dtControllers", "micro\controllers\admin\popo\ControllerAction", $controllers);
177
		$dt->setFields(["controller","action","dValues"]);
178
		$dt->setIdentifierFunction(function($i,$instance){return \urlencode($instance->getController());});
179
		$dt->setCaptions(["Controller","Action [routes]","Default values"]);
180
		$dt->setValueFunction("controller", function($v,$instance,$index){
0 ignored issues
show
Unused Code introduced by
The parameter $index is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
181
			$bt=new HtmlButton("bt-".\urlencode($v),$v);
182
			$bt->setSize("large");
183
			$bt->addIcon("heartbeat",true,true);
184
			$bt->setToggle();
185
			$bt->onClick("$(\"tr[data-ajax='".\urlencode($instance->getController())."'] td:not([rowspan])\").toggle(!$(this).hasClass('active'));");
186
			return $bt;
187
		});
188
		$dt->setValueFunction("action", function($v,$instance,$index){
0 ignored issues
show
Unused Code introduced by
The parameter $index is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
189
			$params=$instance->getParameters();
190
			\array_walk($params, function(&$item){ $item= $item->name;});
191
			$params= " (".\implode(" , ", $params).")";
192
			$v=new HtmlSemDoubleElement("","span","","<b>".$v."</b>");
193
			$v->setProperty("style", "color: #3B83C0;");
194
			$v->addIcon("lightning");
195
			$v.=new HtmlSemDoubleElement("","span","",$params);
196
			$annots=$instance->getAnnots();
197
			foreach ($annots as $path=>$annotDetail){
198
				$lbl=new HtmlLabel("",$path,"car");
199
				$lbl->setProperty("data-ajax", \htmlspecialchars(($path)));
200
				$lbl->addClass("_route");
201
				$v.="&nbsp;".$lbl;
202
			}
203
			return $v;
204
		});
205
		$dt->onPreCompile(function($dt){
206
			$dt->getHtmlComponent()->mergeIdentiqualValues(0);
207
		});
208
		$dt->setEdition(true);
209
		$dt->addClass("compact");
210
		return $dt;
211
	}
212
213
	public function getCacheDataTable($cacheFiles){
214
		$dt=$this->jquery->semantic()->dataTable("dtCacheFiles", "micro\controllers\admin\popo\CacheFile", $cacheFiles);
215
		$dt->setFields(["type","name","timestamp","size"]);
216
		$dt->setCaptions(["Type","Name","Timestamp","Size",""]);
217
		$dt->setValueFunction("type", function($v,$instance,$index){
0 ignored issues
show
Unused Code introduced by
The parameter $index is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
218
			$item=$this->jquery->semantic()->htmlDropdown("dd-type-".$v,$v);
219
			$item->addItems(["Delete all","(Re-)Init cache"]);
220
			$item->setPropertyValues("data-ajax", $v);
221
			$item->getItem(0)->addClass("_delete-all");
222
			if($instance->getFile()==="")
223
				$item->getItem(0)->setDisabled();
224
			$item->getItem(1)->addClass("_init");
225
			if($instance->getType()!=="Models" && $instance->getType()!=="Controllers")
226
				$item->getItem(1)->setDisabled();
227
			$item->asButton()->addIcon("folder",true,true);
228
			return $item;
229
		});
230
		$dt->addDeleteButton(true,[],function($o,$instance){if($instance->getFile()=="")$o->setDisabled();});
231
		$dt->setIdentifierFunction("getFile");
232
		$dt->setValueFunction("timestamp", function($v){
233
			if($v!=="")
234
				return date(DATE_RFC2822,$v);
235
		});
236
		$dt->setValueFunction("size", function($v){
237
			if($v!=="")
238
			return self::formatBytes($v);
239
		});
240
		$dt->onPreCompile(function($dt){
241
			$dt->getHtmlComponent()->mergeIdentiqualValues(0);
242
		});
243
		$this->jquery->postFormOnClick("._delete", $this->controller->_getAdminFiles()->getAdminBaseRoute()."/deleteCacheFile", "frmCache","#dtCacheFiles tbody",["jqueryDone"=>"replaceWith","params"=>"{toDelete:$(this).attr('data-ajax')}"]);
244
		$this->jquery->postFormOnClick("._delete-all", $this->controller->_getAdminFiles()->getAdminBaseRoute()."/deleteAllCacheFiles", "frmCache","#dtCacheFiles tbody",["jqueryDone"=>"replaceWith","params"=>"{type:$(this).attr('data-ajax')}"]);
245
		$this->jquery->postFormOnClick("._init", $this->controller->_getAdminFiles()->getAdminBaseRoute()."/initCacheType", "frmCache","#dtCacheFiles tbody",["jqueryDone"=>"replaceWith","params"=>"{type:$(this).attr('data-ajax')}"]);
246
		return $dt;
247
	}
248
249
	public function getConfigDataElement($config){
250
		$de=$this->jquery->semantic()->dataElement("deConfig", $config);
251
		$fields=\array_keys($config);
252
		$de->setFields($fields);
253
		$de->setCaptions($fields);
254
		$de->setValueFunction("database", function($v,$instance,$index){
0 ignored issues
show
Unused Code introduced by
The parameter $instance is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $index is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
255
			$dbDe=new DataElement("",$v);
256
			$dbDe->setFields(["dbName","serverName","port","user","password","cache"]);
257
			$dbDe->setCaptions(["dbName","serverName","port","user","password","cache"]);
258
			return $dbDe;
259
		});
260
		$de->setValueFunction("templateEngineOptions", function($v,$instance,$index){
0 ignored issues
show
Unused Code introduced by
The parameter $instance is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $index is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
261
			$teoDe=new DataElement("",$v);
262
			$teoDe->setFields(["cache"]);
263
			$teoDe->setCaptions(["cache"]);
264
			$teoDe->fieldAsCheckbox("cache",["class"=>"ui checkbox slider"]);
265
			return $teoDe;
266
		});
267
		$de->setValueFunction("mvcNS", function($v,$instance,$index){
0 ignored issues
show
Unused Code introduced by
The parameter $instance is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $index is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
268
			$mvcDe=new DataElement("",$v);
269
			$mvcDe->setFields(["models","controllers"]);
270
			$mvcDe->setCaptions(["Models","Controllers"]);
271
			return $mvcDe;
272
		});
273
		$de->setValueFunction("di", function($v,$instance,$index) use($config){
0 ignored issues
show
Unused Code introduced by
The parameter $instance is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $index is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
274
			$diDe=new DataElement("",$v);
275
			$keys=\array_keys($config["di"]);
276
			$diDe->setFields($keys);
277
			foreach ($keys as $key){
278
				$diDe->setValueFunction($key, function($value) use ($config,$key){
0 ignored issues
show
Unused Code introduced by
The parameter $value is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
279
					$r =$config['di'][$key];
280
					return \nl2br(self::closure_dump($r));
281
282
				});
283
			}
284
			return $diDe;
285
		});
286
		$de->fieldAsCheckbox("test",["class"=>"ui checkbox slider"]);
287
		$de->fieldAsCheckbox("debug",["class"=>"ui checkbox slider"]);
288
		return $de;
289
	}
290
291
	private static function closure_dump(\Closure $c) {
292
		$str = 'function (';
293
		$r = new \ReflectionFunction($c);
294
		$params = array();
295
		foreach($r->getParameters() as $p) {
296
			$s = '';
297
			if($p->isArray()) {
298
				$s .= 'array ';
299
			} else if($p->getClass()) {
300
				$s .= $p->getClass()->name . ' ';
301
			}
302
			if($p->isPassedByReference()){
303
				$s .= '&';
304
			}
305
			$s .= '$' . $p->name;
306
			if($p->isOptional()) {
307
				$s .= ' = ' . \var_export($p->getDefaultValue(), TRUE);
308
			}
309
			$params []= $s;
310
		}
311
		$str .= \implode(', ', $params);
312
		$str .= '){' . PHP_EOL;
313
		$lines = file($r->getFileName());
314
		for($l = $r->getStartLine(); $l < $r->getEndLine(); $l++) {
315
			$str .= $lines[$l];
316
		}
317
		return $str;
318
	}
319
320
	private static function formatBytes($size, $precision = 2){
321
		$base = log($size, 1024);
322
		$suffixes = array('o', 'Ko', 'Mo', 'Go', 'To');
323
		return round(pow(1024, $base - floor($base)), $precision) .' '. $suffixes[floor($base)];
324
	}
325
326
	protected function relationMembersInForm($form,$instance,$className){
327
		$relations = OrmUtils::getFieldsInRelations($className);
328
		foreach ($relations as $member){
329
			if($this->controller->_getAdminData()->getUpdateManyToOneInForm() && OrmUtils::getAnnotationInfoMember($className, "#manyToOne",$member)!==false){
330
				$this->manyToOneFormField($form, $member, $className, $instance);
331
			}elseif($this->controller->_getAdminData()->getUpdateOneToManyInForm() && ($annot=OrmUtils::getAnnotationInfoMember($className, "#oneToMany",$member))!==false){
332
				$this->oneToManyFormField($form, $member, $instance,$annot);
333
			}elseif($this->controller->_getAdminData()->getUpdateManyToManyInForm() && ($annot=OrmUtils::getAnnotationInfoMember($className, "#manyToMany",$member))!==false){
334
				$this->manyToManyFormField($form, $member, $instance,$annot);
335
			}
336
		}
337
	}
338
339
	protected function manyToOneFormField(DataForm $form,$member,$className,$instance){
340
		$joinColumn=OrmUtils::getAnnotationInfoMember($className, "#joinColumn", $member);
341
		if($joinColumn){
342
			$fkObject=Reflexion::getMemberValue($instance, $member);
343
			$fkClass=$joinColumn["className"];
344
			if($fkObject===null){
345
				$fkObject=new $fkClass();
346
			}
347
			$fkId=OrmUtils::getFirstKey($fkClass);
348
			$fkIdGetter="get".\ucfirst($fkId);
349
			if(\method_exists($fkObject, "__toString") && \method_exists($fkObject, $fkIdGetter)){
350
				$fkField=$joinColumn["name"];
351
				$fkValue=OrmUtils::getFirstKeyValue($fkObject);
352
				if(!Reflexion::setMemberValue($instance, $fkField, $fkValue)){
353
					$instance->{$fkField}=OrmUtils::getFirstKeyValue($fkObject);
354
					$form->addField($fkField);
355
				}
356
				$form->fieldAsDropDown($fkField,JArray::modelArray(DAO::getAll($fkClass),$fkIdGetter,"__toString"));
357
				$form->setCaption($fkField, \ucfirst($member));
358
			}
359
		}
360
	}
361
	protected function oneToManyFormField(DataForm $form,$member,$instance,$annot){
362
		$newField=$member."Ids";
363
		$fkClass=$annot["className"];
364
		$fkId=OrmUtils::getFirstKey($fkClass);
365
		$fkIdGetter="get".\ucfirst($fkId);
366
		$fkInstances=DAO::getOneToMany($instance, $member);
367
		$form->addField($newField);
368
		$ids=\array_map(function($elm) use($fkIdGetter){return $elm->{$fkIdGetter}();},$fkInstances);
369
		$instance->{$newField}=\implode(",", $ids);
370
		$form->fieldAsDropDown($newField,JArray::modelArray(DAO::getAll($fkClass),$fkIdGetter,"__toString"),true);
371
		$form->setCaption($newField, \ucfirst($member));
372
	}
373
374
	protected function manyToManyFormField(DataForm $form,$member,$instance,$annot){
375
		$newField=$member."Ids";
376
		$fkClass=$annot["targetEntity"];
377
		$fkId=OrmUtils::getFirstKey($fkClass);
378
		$fkIdGetter="get".\ucfirst($fkId);
379
		$fkInstances=DAO::getManyToMany($instance, $member);
380
		$form->addField($newField);
381
		$ids=\array_map(function($elm) use($fkIdGetter){return $elm->{$fkIdGetter}();},$fkInstances);
382
		$instance->{$newField}=\implode(",", $ids);
383
		$form->fieldAsDropDown($newField,JArray::modelArray($this->controller->_getAdminData()->getManyToManyDatas($fkClass, $instance, $member),$fkIdGetter,"__toString"),true,["jsCallback"=>function($elm){$elm->getField()->asSearch();}]);
384
		$form->setCaption($newField, \ucfirst($member));
385
	}
386
}
387