Total Complexity | 53 |
Total Lines | 382 |
Duplicated Lines | 0 % |
Changes | 2 | ||
Bugs | 0 | Features | 0 |
Complex classes like FormElement 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 FormElement, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
13 | abstract class FormElement implements FormElementInterface |
||
14 | { |
||
15 | use XMLHelper; |
||
16 | |||
17 | /** @var FormGenerator the FormGenerator this element belongs to */ |
||
18 | protected FormGenerator $oFG; |
||
19 | /** @var FormCollection the parent element - only FormGenerator must has no parent */ |
||
20 | protected ?FormCollection $oParent = null; |
||
21 | /** @var int tab index of the element if it can get focus */ |
||
22 | protected int $iTabindex = -1; |
||
23 | /** @var int col inside current line */ |
||
24 | protected int $iCol = 0; |
||
25 | /** @var string element name */ |
||
26 | protected string $strName = ''; |
||
27 | /** @var string element id */ |
||
28 | protected string $strID = ''; |
||
29 | /** @var string CSS class of the element */ |
||
30 | protected string $strClass = ''; |
||
31 | /** @var FormFlags flags that specify the appearance and behaviour */ |
||
32 | protected FormFlags $oFlags; |
||
33 | /** @var array attributes of the element */ |
||
34 | protected ?array $aAttrib = null; |
||
35 | /** @var array (CSS) styles of the element */ |
||
36 | protected ?array $aStyle = null; |
||
37 | |||
38 | /** |
||
39 | * Create any kind of form element. |
||
40 | * @see FormFlags |
||
41 | * @param int $wFlags any combination of FormFlag constants |
||
42 | */ |
||
43 | public function __construct(int $wFlags) |
||
44 | { |
||
45 | $this->oFlags = new FormFlags($wFlags); |
||
46 | } |
||
47 | |||
48 | /** |
||
49 | * Create the form element from the given XML-element. |
||
50 | * Because several subclasses of FormElement has different constructors, we |
||
51 | * need one uniform static function to be able to create all elements |
||
52 | * independent from the subclass within a loop. |
||
53 | * In the derived classes this function must return an instance of the |
||
54 | * requested class. |
||
55 | * @param \DOMElement $oXMLElement the XML-element containing the information |
||
56 | * @param FormCollection $oFormParent the form parent of the element to create |
||
57 | * @return FormElement|NULL the created element |
||
58 | * @internal |
||
59 | */ |
||
60 | abstract static public function fromXML(\DOMElement $oXMLElement, FormCollection $oFormParent) : ?FormElement; |
||
61 | |||
62 | /** |
||
63 | * In addition to the parameters needed by the constructor of each separate class, |
||
64 | * some further attribs can be loaded after creation. |
||
65 | * In contrast to the static fromXML() method, this method can be defined in parent |
||
66 | * classes for general attributes. |
||
67 | * In the derived classes this method should called it's parent down through all |
||
68 | * parent-classes! |
||
69 | * @param \DOMElement $oXMLElement |
||
70 | * @internal |
||
71 | */ |
||
72 | public function readAdditionalXML(\DOMElement $oXMLElement) : void |
||
73 | { |
||
74 | if (($strID = self::getAttribString($oXMLElement, 'id')) !== null) { |
||
75 | $this->setID($strID); |
||
76 | } |
||
77 | if (($strStyle = self::getAttribString($oXMLElement, 'style')) !== null) { |
||
78 | $this->parseStyle($strStyle); |
||
79 | } |
||
80 | if (($strCSSClass = self::getAttribString($oXMLElement, 'class')) !== null) { |
||
81 | $this->addClass($strCSSClass); |
||
82 | } |
||
83 | $this->aAttrib = $this->readElementAttributes($oXMLElement, $this->aAttrib); |
||
84 | } |
||
85 | |||
86 | /** |
||
87 | * Return the FormGenerator this element belongs to. |
||
88 | * @return FormGenerator |
||
89 | * @internal |
||
90 | */ |
||
91 | public function getFG() : ?FormGenerator |
||
92 | { |
||
93 | return $this->oFG; |
||
94 | } |
||
95 | |||
96 | /** |
||
97 | * Set the parent of this element. |
||
98 | * The Formgenerator of the parent is adopted for this element. |
||
99 | * If there are global flags set for the FormGenerator, this flags are added. |
||
100 | * @param FormCollection $oParent |
||
101 | * @internal |
||
102 | */ |
||
103 | public function setParent(FormCollection $oParent) : void |
||
104 | { |
||
105 | $this->oParent = $oParent; |
||
106 | $this->oFG = $oParent->oFG; |
||
107 | $this->addFlags($this->oFG->getGlobalFlags()); |
||
108 | $this->onParentSet(); |
||
109 | } |
||
110 | |||
111 | /** |
||
112 | * Set the current col. |
||
113 | * If this element is added as a child of a FormLine, the column is set in |
||
114 | * order to be able to calculate the correct width of the element. |
||
115 | * @param int $iCol |
||
116 | * @internal |
||
117 | */ |
||
118 | public function setCol(int $iCol) : void |
||
119 | { |
||
120 | $this->iCol = $iCol; |
||
121 | } |
||
122 | |||
123 | /** |
||
124 | * Set ID for the element. |
||
125 | * @param string $strID |
||
126 | */ |
||
127 | public function setID(string $strID) : void |
||
130 | } |
||
131 | |||
132 | /** |
||
133 | * Set text for the elements title attribute. |
||
134 | * @param string $strTitle |
||
135 | */ |
||
136 | public function setTitle(string $strTitle) : void |
||
137 | { |
||
138 | if (strlen($strTitle) > 0) { |
||
139 | $this->addAttribute('title', $strTitle); |
||
140 | } |
||
141 | } |
||
142 | |||
143 | /** |
||
144 | * Set the tab index of the element. |
||
145 | * Method is called from the PageGenerator after an element is added to the form. |
||
146 | * @param int $iTabindex |
||
147 | * @return int the number of indexes, the element needs |
||
148 | * @internal |
||
149 | */ |
||
150 | public function setTabindex(/** @scrutinizer ignore-unused */ int $iTabindex) : int |
||
153 | } |
||
154 | |||
155 | /** |
||
156 | * Add flags to element. |
||
157 | * @param int $wFlags |
||
158 | */ |
||
159 | public function addFlags(int $wFlags) : void |
||
162 | } |
||
163 | |||
164 | /** |
||
165 | * Add any attribute. |
||
166 | * Attributes with null value are ignored! |
||
167 | * If the attribute allready exist, the value will be overwritten. |
||
168 | * @param string $strName attribute name |
||
169 | * @param string $strValue attribute value |
||
170 | */ |
||
171 | public function addAttribute(string $strName, ?string $strValue = '') : void |
||
172 | { |
||
173 | if ($strValue === null) { |
||
174 | return; |
||
175 | } |
||
176 | $strName = strtolower($strName); |
||
177 | if ($this->aAttrib == null) { |
||
178 | $this->aAttrib = array(); |
||
179 | } |
||
180 | if ($strName == 'style') { |
||
181 | // style should no longer be set through AddAttribute() |
||
182 | trigger_error('use AddStyle() to define additional styles for element!', E_USER_ERROR); |
||
183 | } |
||
184 | $this->aAttrib[$strName] = $strValue; |
||
185 | } |
||
186 | |||
187 | /** |
||
188 | * Add any style. |
||
189 | * If the style allready exist, the value will be overwritten. |
||
190 | * @param string $strName style |
||
191 | * @param string $strValue value |
||
192 | */ |
||
193 | public function addStyle(string $strName, string $strValue) : void |
||
194 | { |
||
195 | $strName = strtolower($strName); |
||
196 | if ($this->aStyle == null) { |
||
197 | $this->aStyle = array(); |
||
198 | } |
||
199 | $this->aStyle[$strName] = $strValue; |
||
200 | } |
||
201 | |||
202 | /** |
||
203 | * Set the CSS class of the element. |
||
204 | * Any previously setting will be overwritten. |
||
205 | * @param string $strClass |
||
206 | */ |
||
207 | public function setClass(string $strClass) : void |
||
208 | { |
||
209 | $this->strClass = $strClass; |
||
210 | } |
||
211 | |||
212 | /** |
||
213 | * Add additional class to element. |
||
214 | * Class is added to the existing classname separated with a blank |
||
215 | * @param string $strClass |
||
216 | */ |
||
217 | public function addClass(string $strClass) : void |
||
218 | { |
||
219 | if (strlen($this->strClass) > 0) { |
||
220 | $this->strClass .= ' '; |
||
221 | } |
||
222 | $this->strClass .= $strClass; |
||
223 | } |
||
224 | |||
225 | /** |
||
226 | * Get CSS styles related to this element. |
||
227 | * This method gives each element the chance to add special styles to the |
||
228 | * current page. <br/> |
||
229 | * <b>This method is only called for elements having member bCreateStyle set to true!</b> |
||
230 | * @return string |
||
231 | * @internal |
||
232 | */ |
||
233 | public function getStyle() : string |
||
234 | { |
||
235 | return ''; |
||
236 | } |
||
237 | |||
238 | /** |
||
239 | * @return string |
||
240 | * @internal |
||
241 | */ |
||
242 | abstract public function getHTML() : string; |
||
243 | |||
244 | /** |
||
245 | * Method called, after parent amd formgenerator is set properly. |
||
246 | * Enhancing classes can use this method, to initialize properties that |
||
247 | * nneds the parent or formgenerator (... configuration, global settings) |
||
248 | */ |
||
249 | protected function onParentSet() : void |
||
250 | { |
||
251 | } |
||
252 | |||
253 | /** |
||
254 | * Build the 'container' div arround the current element. |
||
255 | * Additional styles (alignment, ...) can be passed. |
||
256 | * @param string $strStyle |
||
257 | * @return string |
||
258 | */ |
||
259 | protected function buildContainerDiv(string $strStyle = '') : string |
||
260 | { |
||
261 | if (strpos($strStyle, 'float') === false) { |
||
262 | $strStyle = 'float: left; ' . $strStyle; |
||
263 | } |
||
264 | $strWidth = ($this->oParent ? $this->oParent->getColWidth($this->iCol) : ''); |
||
265 | if (!empty($strWidth)) { |
||
266 | $strStyle = rtrim($strStyle, '; '); |
||
267 | $strStyle .= '; width: ' . $strWidth . ';'; |
||
268 | } |
||
269 | $strHTML = '<div style="' . $strStyle . '">'; |
||
270 | |||
271 | return $strHTML; |
||
272 | } |
||
273 | |||
274 | /** |
||
275 | * Build the style attribute for the element. |
||
276 | * @return string |
||
277 | */ |
||
278 | protected function buildStyle() : string |
||
279 | { |
||
280 | $strStyle = ''; |
||
281 | if ($this->aStyle != null) { |
||
282 | $strStyle = ' style="'; |
||
283 | foreach ($this->aStyle as $strName => $strValue) { |
||
284 | $strStyle .= ' ' . $strName . ': ' . $strValue . ';'; |
||
285 | } |
||
286 | $strStyle .= '"'; |
||
287 | } |
||
288 | return $strStyle; |
||
289 | } |
||
290 | |||
291 | /** |
||
292 | * Build all defined attributes for the element. |
||
293 | * @return string |
||
294 | */ |
||
295 | protected function buildAttributes() : string |
||
296 | { |
||
297 | $strAttrib = ''; |
||
298 | if ($this->aAttrib != null) { |
||
299 | foreach ($this->aAttrib as $strName => $strValue) { |
||
300 | $strAttrib .= ' ' . $strName; |
||
301 | if (strlen($strValue) > 0) { |
||
302 | $strAttrib .= '="' . $strValue . '"'; |
||
303 | } |
||
304 | } |
||
305 | } |
||
306 | return $strAttrib; |
||
307 | } |
||
308 | |||
309 | /** |
||
310 | * Build the markup for the value attribute. |
||
311 | * Retrieve value for the element from the FormData. |
||
312 | * @return string Empty string if no value set, complete attribute if set |
||
313 | */ |
||
314 | protected function buildValue() : string |
||
315 | { |
||
316 | $strHTML = ''; |
||
317 | $strValue = $this->oFG->getData()->getValue($this->strName); |
||
318 | |||
319 | if ($this->oFlags->isSet(FormFlags::TRIM)) { |
||
320 | $strValue = trim($strValue); |
||
321 | } |
||
322 | if (!$this->oFlags->isSet(FormFlags::NO_ZERO) || ($strValue != 0 && $strValue != '0')) { |
||
323 | $strHTML = ' value="' . str_replace('"', '"', $strValue) . '"'; |
||
324 | } |
||
325 | return $strHTML; |
||
326 | } |
||
327 | |||
328 | /** |
||
329 | * Build the markup for the class attribute. |
||
330 | * @return string Empty string if no class set, complete attribute if set |
||
331 | */ |
||
332 | protected function buildClass() : string |
||
333 | { |
||
334 | $strClass = ''; |
||
335 | if (!empty($this->strClass)) { |
||
336 | $strClass .= ' class="' . $this->strClass . '"'; |
||
337 | } |
||
338 | return $strClass; |
||
339 | } |
||
340 | |||
341 | /** |
||
342 | * Build the markup for the ID attribute. |
||
343 | * @return string Empty string if no id set, complete attribute if set |
||
344 | */ |
||
345 | protected function buildID() : string |
||
346 | { |
||
347 | $strID = ''; |
||
348 | if (!empty($this->strID)) { |
||
349 | $strID .= ' id="' . $this->strID . '"'; |
||
350 | } |
||
351 | return $strID; |
||
352 | } |
||
353 | |||
354 | /** |
||
355 | * Build the markup for the tabindex attribute. |
||
356 | * @return string Empty string if $iTabindex = 0, complete attribute if set |
||
357 | */ |
||
358 | protected function buildTabindex() : string |
||
365 | } |
||
366 | |||
367 | /** |
||
368 | * Parse a given style attribute into the components it contains. |
||
369 | * @param string $strStyle |
||
370 | */ |
||
371 | protected function parseStyle($strStyle) : void |
||
383 | } |
||
384 | } |
||
385 | } |
||
386 | |||
387 | /** |
||
388 | * Get the requested attribute. |
||
389 | * @param string $strName |
||
390 | * @return string|NULL return null, if attribute not set |
||
391 | */ |
||
392 | protected function getAttribute(string $strName) : ?string |
||
395 | } |
||
396 | } |
||
397 | |||
398 |