Passed
Branch master (7dd754)
by Jean-Christophe
16:28
created

FormModelViewerTrait   B

Complexity

Total Complexity 48

Size/Duplication

Total Lines 301
Duplicated Lines 0 %

Test Coverage

Coverage 75.71%

Importance

Changes 0
Metric Value
wmc 48
eloc 158
dl 0
loc 301
ccs 134
cts 177
cp 0.7571
rs 8.5599
c 0
b 0
f 0

17 Methods

Rating   Name   Duplication   Size   Complexity  
A manyToOneFormField() 0 18 6
A defaultEditMemberParams() 0 2 1
A getEditMemberParams() 0 2 1
A getEditMemberParams_() 0 6 3
A manyToManyFormField() 0 14 1
A oneToManyFormField() 0 12 1
B setFormFieldsComponent_() 0 27 10
B getMemberForm() 0 48 6
A getForm() 0 23 1
A getFormCaptions() 0 2 1
A isModal() 0 2 1
A setFormFieldsComponent() 0 2 1
A setMemberFormFieldsComponent() 0 2 1
A onGenerateFormField() 0 8 3
A getFormTitle() 0 6 2
A relationMembersInForm() 0 9 6
A setFormFields_() 0 10 3

How to fix   Complexity   

Complex Class

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

1
<?php
2
3
namespace Ubiquity\controllers\crud\viewers\traits;
4
5
use Ajax\semantic\html\collections\form\HtmlFormField;
6
use Ajax\semantic\html\collections\form\HtmlFormInput;
7
use Ajax\semantic\html\elements\HtmlButton;
8
use Ajax\semantic\html\elements\HtmlIconGroups;
9
use Ajax\semantic\widgets\dataform\DataForm;
10
use Ajax\service\JArray;
11
use Ubiquity\controllers\crud\EditMemberParams;
12
use Ubiquity\orm\DAO;
13
use Ubiquity\orm\OrmUtils;
14
use Ubiquity\orm\parser\Reflexion;
15
16
/**
17
 * Associated with a CRUDController class (part of ModelViewer)
18
 * Responsible of the display of the form
19
 * Ubiquity\controllers\crud\viewers\traits$FormModelViewerTrait
20
 * This class is part of Ubiquity
21
 *
22
 * @author jcheron <[email protected]>
23
 * @version 1.0.1
24
 * @property \Ajax\JsUtils $jquery
25
 */
26
trait FormModelViewerTrait {
27
28 3
	protected function relationMembersInForm($form, $instance, $className, $fields, $relations) {
29 3
		foreach ( $relations as $field => $member ) {
30 3
			if (array_search ( $field, $fields ) !== false) {
31 1
				if (OrmUtils::getAnnotationInfoMember ( $className, "#manyToOne", $member ) !== false) {
32 1
					$this->manyToOneFormField ( $form, $member, $className, $instance );
33
				} elseif (($annot = OrmUtils::getAnnotationInfoMember ( $className, "#oneToMany", $member )) !== false) {
34
					$this->oneToManyFormField ( $form, $member, $instance, $annot );
35
				} elseif (($annot = OrmUtils::getAnnotationInfoMember ( $className, "#manyToMany", $member )) !== false) {
36 3
					$this->manyToManyFormField ( $form, $member, $instance, $annot );
37
				}
38
			}
39
		}
40 3
	}
41
42 1
	protected function manyToOneFormField(DataForm $form, $member, $className, $instance) {
43 1
		$joinColumn = OrmUtils::getAnnotationInfoMember ( $className, "#joinColumn", $member );
44 1
		if ($joinColumn) {
45 1
			$fkObject = Reflexion::getMemberValue ( $instance, $member );
46 1
			$fkClass = $joinColumn ["className"];
47 1
			if ($fkObject === null) {
48
				$fkObject = new $fkClass ();
49
			}
50 1
			$fkId = OrmUtils::getFirstKey ( $fkClass );
51 1
			$fkIdGetter = "get" . \ucfirst ( $fkId );
52 1
			if (\method_exists ( $fkObject, "__toString" ) && \method_exists ( $fkObject, $fkIdGetter )) {
53 1
				$fkField = $joinColumn ["name"];
54 1
				$fkValue = OrmUtils::getFirstKeyValue ( $fkObject );
55 1
				if (! Reflexion::setMemberValue ( $instance, $fkField, $fkValue )) {
56 1
					$instance->{$fkField} = OrmUtils::getFirstKeyValue ( $fkObject );
57
				}
58 1
				$form->fieldAsDropDown ( $fkField, JArray::modelArray ( $this->controller->_getAdminData ()->getManyToOneDatas ( $fkClass, $instance, $member ), $fkIdGetter, "__toString" ) );
59 1
				$form->setCaption ( $fkField, \ucfirst ( $member ) );
60
			}
61
		}
62 1
	}
63
64
	protected function oneToManyFormField(DataForm $form, $member, $instance, $annot) {
65
		$newField = $member . "Ids";
66
		$fkClass = $annot ["className"];
67
		$fkId = OrmUtils::getFirstKey ( $fkClass );
68
		$fkIdGetter = "get" . \ucfirst ( $fkId );
69
		$fkInstances = DAO::getOneToMany ( $instance, $member );
70
		$ids = \array_map ( function ($elm) use ($fkIdGetter) {
71
			return $elm->{$fkIdGetter} ();
72
		}, $fkInstances );
73
		$instance->{$newField} = \implode ( ",", $ids );
74
		$form->fieldAsDropDown ( $newField, JArray::modelArray ( $this->controller->_getAdminData ()->getOneToManyDatas ( $fkClass, $instance, $member ), $fkIdGetter, "__toString" ), true );
75
		$form->setCaption ( $newField, \ucfirst ( $member ) );
76
	}
77
78
	protected function manyToManyFormField(DataForm $form, $member, $instance, $annot) {
79
		$newField = $member . "Ids";
80
		$fkClass = $annot ["targetEntity"];
81
		$fkId = OrmUtils::getFirstKey ( $fkClass );
82
		$fkIdGetter = "get" . \ucfirst ( $fkId );
83
		$fkInstances = DAO::getManyToMany ( $instance, $member );
84
		$ids = \array_map ( function ($elm) use ($fkIdGetter) {
85
			return $elm->{$fkIdGetter} ();
86
		}, $fkInstances );
87
		$instance->{$newField} = \implode ( ",", $ids );
88
		$form->fieldAsDropDown ( $newField, JArray::modelArray ( $this->controller->_getAdminData ()->getManyToManyDatas ( $fkClass, $instance, $member ), $fkIdGetter, "__toString" ), true, [ "jsCallback" => function ($elm) {
89
			$elm->getField ()->asSearch ();
90
		} ] );
91
		$form->setCaption ( $newField, \ucfirst ( $member ) );
92
	}
93
94
	/**
95
	 *
96
	 * @return \Ubiquity\controllers\crud\EditMemberParams[]
97
	 */
98 7
	public function getEditMemberParams() {
99 7
		return $this->defaultEditMemberParams ();
100
	}
101
102
	/**
103
	 *
104
	 * @param string $part
105
	 * @return \Ubiquity\controllers\crud\EditMemberParams
106
	 */
107 2
	protected function getEditMemberParams_($part) {
108 2
		$params = $this->getEditMemberParams ();
109 2
		if ($params && isset ( $params [$part] )) {
110 2
			return $params [$part];
111
		}
112
		return new EditMemberParams ();
113
	}
114
115
	/**
116
	 *
117
	 * @return \Ubiquity\controllers\crud\EditMemberParams[]
118
	 */
119 7
	protected function defaultEditMemberParams() {
120 7
		return [ "dataTable" => EditMemberParams::dataTable (),"dataElement" => EditMemberParams::dataElement () ];
121
	}
122
123
	/**
124
	 * Returns the form for adding or modifying an object
125
	 *
126
	 * @param string $identifier
127
	 * @param object $instance the object to add or modify
128
	 * @return \Ajax\semantic\widgets\dataform\DataForm
129
	 */
130 3
	public function getForm($identifier, $instance) {
131 3
		$form = $this->jquery->semantic ()->dataForm ( $identifier, $instance );
132 3
		$form->setLibraryId ( "frmEdit" );
133 3
		$className = \get_class ( $instance );
134 3
		$fields = array_unique ( $this->controller->_getAdminData ()->getFormFieldNames ( $className, $instance ) );
135 3
		$relFields = OrmUtils::getFieldsInRelations_ ( $className );
136
137 3
		$this->setFormFields_ ( $fields, $relFields );
138 3
		array_unshift ( $fields, "_message" );
139 3
		$form->setFields ( $fields );
140
141 3
		$fieldTypes = OrmUtils::getFieldTypes ( $className );
142 3
		$this->setFormFieldsComponent ( $form, $fieldTypes );
143 3
		$this->relationMembersInForm ( $form, $instance, $className, $fields, $relFields );
144 3
		OrmUtils::setFieldToMemberNames ( $fields, $relFields );
145 3
		$form->setCaptions ( $this->getFormCaptions ( $fields, $className, $instance ) );
146 3
		$message = $this->getFormTitle ( $form, $instance );
147 3
		$form->setCaption ( "_message", $message ["subMessage"] );
148 3
		$form->fieldAsMessage ( "_message", [ "icon" => $message ["icon"] ] );
149 3
		$instance->_message = $message ["message"];
150 3
		$form->setSubmitParams ( $this->controller->_getBaseRoute () . "/update", "#frm-add-update" );
151 3
		$form->onGenerateField ( [ $this,'onGenerateFormField' ] );
152 3
		return $form;
153
	}
154
155
	/**
156
	 * Returns a form for member editing
157
	 *
158
	 * @param string $identifier
159
	 * @param object $instance
160
	 * @param string $member
161
	 * @param string $td
162
	 * @param string $part
163
	 * @return \Ajax\semantic\widgets\dataform\DataForm
164
	 */
165 2
	public function getMemberForm($identifier, $instance, $member, $td, $part) {
166 2
		$editMemberParams = $this->getEditMemberParams_ ( $part );
167
168 2
		$form = $this->jquery->semantic ()->dataForm ( $identifier, $instance );
169 2
		$form->on ( "dblclick", "", true, true );
170 2
		$form->setProperty ( "onsubmit", "return false;" );
171 2
		$form->addClass ( "_memberForm" );
172 2
		$className = \get_class ( $instance );
173 2
		$fields = [ "id",$member ];
174 2
		$relFields = OrmUtils::getFieldsInRelations_ ( $className );
175 2
		$hasRelations = $this->setFormFields_ ( $fields, $relFields );
176 2
		$form->setFields ( $fields );
177 2
		$fieldTypes = OrmUtils::getFieldTypes ( $className );
178 2
		$form->fieldAsHidden ( 0 );
179 2
		$this->setMemberFormFieldsComponent ( $form, $fieldTypes );
180 2
		if ($hasRelations) {
181
			$this->relationMembersInForm ( $form, $instance, $className, $fields, $relFields );
182
		}
183 2
		$form->setCaptions ( [ "","" ] );
184
		$form->onGenerateField ( function (HtmlFormField $f, $nb) use ($identifier, $editMemberParams) {
185 2
			if ($nb == 1) {
186 2
				$f->setSize ( "mini" );
187 2
				if ($editMemberParams->getHasButtons ()) {
188 2
					$btO = HtmlButton::icon ( "btO", "check" )->addClass ( "green mini compact" )->onClick ( "\$('#" . $identifier . "').trigger('validate');", true, true );
189 2
					$btC = HtmlButton::icon ( "btC", "close" )->addClass ( "mini compact" )->onClick ( "\$('#" . $identifier . "').trigger('endEdit');" );
190 2
					$f->wrap ( "<div class='fields' style='margin:0;'>", [ $btO,$btC,"</div>" ] );
191 2
					if (! $editMemberParams->getHasPopup ()) {
192 1
						$f->setWidth ( 16 )->setProperty ( "style", "padding-left:0;" );
193
					}
194
				}
195 2
				$f->on ( "keydown", "if(event.which == 13) {\$('#" . $identifier . "').trigger('validate');}if(event.keyCode===27) {\$('#" . $identifier . "').trigger('endEdit');}" );
196 2
				$f->onClick ( "return false;", true, true );
197
			} else {
198 2
				$f->setProperty ( "style", "display: none;" );
199
			}
200 2
		} );
201 2
		$form->setSubmitParams ( $this->controller->_getBaseRoute () . "/updateMember/" . $member . "/" . $editMemberParams->getUpdateCallback (), "#" . $td, [ "attr" => "","hasLoader" => false,"jsCallback" => "$(self).remove();","jqueryDone" => "html" ] );
202 2
		if ($editMemberParams->getHasPopup ()) {
203 1
			$endEdit = "\$('#" . $identifier . "').html();\$('.popup').hide();\$('#" . $td . "').popup('destroy');";
204 1
			$validate = $endEdit;
205
		} else {
206 1
			$endEdit = "let td=\$('#" . $td . "');td.html(td.data('originalText'));";
207 1
			$validate = "";
208
		}
209 2
		$form->on ( "endEdit", $endEdit );
210 2
		$form->on ( "validate", "\$('#" . $identifier . "').form('submit');" . $validate );
211 2
		$this->jquery->execAtLast ( "$('form').find('input[type=text],textarea,select').filter(':visible:first').focus();" );
212 2
		return $form;
213
	}
214
215 4
	private function setFormFields_(&$fields, $relFields) {
216 4
		$hasRelations = false;
217 4
		$relFields = array_flip ( $relFields );
218 4
		foreach ( $fields as $index => $field ) {
219 4
			if (isset ( $relFields [$field] )) {
220
				$fields [$index] = $relFields [$field];
221 4
				$hasRelations = true;
222
			}
223
		}
224 4
		return $hasRelations;
225
	}
226
227
	/**
228
	 * Returns an associative array defining form message title with keys "icon","message","subMessage"
229
	 *
230
	 * @param DataForm $form
231
	 * @param object $instance
232
	 * @return array the message title
233
	 */
234 3
	protected function getFormTitle($form, $instance) {
235 3
		$type = ($instance->_new) ? "new" : "edit";
236 3
		$messageInfos = [ "new" => [ "icon" => HtmlIconGroups::corner ( "table", "plus", "big" ),"subMessage" => "New object creation" ],"edit" => [ "icon" => HtmlIconGroups::corner ( "table", "edit", "big" ),"subMessage" => "Editing an existing object" ] ];
237 3
		$message = $messageInfos [$type];
238 3
		$message ["message"] = \get_class ( $instance );
239 3
		return $message;
240
	}
241
242
	/**
243
	 * Sets the components for each field
244
	 *
245
	 * @param DataForm $form
246
	 * @param array $fieldTypes associative array of field names (keys) and types (values)
247
	 */
248 3
	public function setFormFieldsComponent(DataForm $form, $fieldTypes) {
249 3
		$this->setFormFieldsComponent_ ( $form, $fieldTypes );
250 3
	}
251
252
	/**
253
	 * Sets the components for each field
254
	 *
255
	 * @param DataForm $form
256
	 * @param array $fieldTypes associative array of field names (keys) and types (values)
257
	 */
258 2
	public function setMemberFormFieldsComponent(DataForm $form, $fieldTypes) {
259 2
		$this->setFormFieldsComponent_ ( $form, $fieldTypes );
260 2
	}
261
262 4
	protected function setFormFieldsComponent_(DataForm $form, $fieldTypes) {
263 4
		foreach ( $fieldTypes as $property => $type ) {
264 4
			switch ($property) {
265 4
				case "password" :
266
					$form->fieldAsInput ( $property, [ "inputType" => "password" ] );
267
					$form->setValidationParams ( [ "inline" => true ] );
268
					break;
269 4
				case "email" :
270 4
				case "mail" :
271
					$form->fieldAsInput ( $property, [ "inputType" => "email","rules" => [ [ "email" ] ] ] );
272
					break;
273
			}
274
275 4
			switch ($type) {
276 4
				case "tinyint(1)" :
277
					$form->fieldAsCheckbox ( $property );
278
					break;
279 4
				case "int" :
280 4
				case "integer" :
281
					$form->fieldAsInput ( $property, [ "inputType" => "number" ] );
282
					break;
283 4
				case "date" :
284
					$form->fieldAsInput ( $property, [ "inputType" => "date" ] );
285
					break;
286 4
				case "datetime" :
287 1
					$form->fieldAsInput ( $property, [ "inputType" => "datetime-local" ] );
288 4
					break;
289
			}
290
		}
291 4
	}
292
293
	/**
294
	 * For doing something when $field is generated in form
295
	 *
296
	 * @param mixed $field
297
	 */
298 3
	public function onGenerateFormField($field, $nb) {
299 3
		if ($field instanceof HtmlFormInput) {
300 3
			if ($field->getDataField ()->getProperty ( 'type' ) == "datetime-local") {
301 1
				$v = $field->getDataField ()->getProperty ( 'value' );
302 1
				$field->getDataField ()->setValue ( date ( "Y-m-d\TH:i:s", strtotime ( $v ) ) );
303
			}
304
		}
305 3
		return;
306
	}
307
308
	/**
309
	 * Condition to determine if the edit or add form is modal for $model objects
310
	 *
311
	 * @param array $objects
312
	 * @param string $model
313
	 * @return boolean
314
	 */
315 7
	public function isModal($objects, $model) {
316 7
		return \count ( $objects ) > 5;
317
	}
318
319
	/**
320
	 * Returns the captions for form fields
321
	 *
322
	 * @param array $captions
323
	 * @param string $className
324
	 */
325 3
	public function getFormCaptions($captions, $className, $instance) {
326 3
		return \array_map ( "ucfirst", $captions );
327
	}
328
}
329
330