]> git.mxchange.org Git - core.git/blob - framework/main/classes/helper/class_BaseHelper.php
Continued:
[core.git] / framework / main / classes / helper / class_BaseHelper.php
1 <?php
2 // Own namespace
3 namespace Org\Mxchange\CoreFramework\Helper;
4
5 // Import framework stuff
6 use Org\Mxchange\CoreFramework\Factory\Object\ObjectFactory;
7 use Org\Mxchange\CoreFramework\Generic\FrameworkInterface;
8 use Org\Mxchange\CoreFramework\Generic\NullPointerException;
9 use Org\Mxchange\CoreFramework\Object\BaseFrameworkSystem;
10 use Org\Mxchange\CoreFramework\Registry\Object\ObjectRegistry;
11 use Org\Mxchange\CoreFramework\Utils\Strings\StringUtils;
12
13 // Import SPL stuff
14 use \BasMethodCallException;
15 use \InvalidArgumentException;
16
17 /**
18  * A generic helper class with generic methods
19  *
20  * @author              Roland Haeder <webmaster@shipsimu.org>
21  * @version             0.0.0
22  * @copyright   Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2023 Core Developer Team
23  * @license             GNU GPL 3.0 or any newer version
24  * @link                http://www.shipsimu.org
25  *
26  * This program is free software: you can redistribute it and/or modify
27  * it under the terms of the GNU General Public License as published by
28  * the Free Software Foundation, either version 3 of the License, or
29  * (at your option) any later version.
30  *
31  * This program is distributed in the hope that it will be useful,
32  * but WITHOUT ANY WARRANTY; without even the implied warranty of
33  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
34  * GNU General Public License for more details.
35  *
36  * You should have received a copy of the GNU General Public License
37  * along with this program. If not, see <http://www.gnu.org/licenses/>.
38  */
39 abstract class BaseHelper extends BaseFrameworkSystem {
40         /**
41          * Instance to the class which provides field values
42          */
43         private $valueInstance = NULL;
44
45         /**
46          * Extra instance to the class which provides field values
47          */
48         private $extraInstance = NULL;
49
50         /**
51          * Rendered content created by the helper class
52          */
53         private $content = '';
54
55         /**
56          * Array with groups
57          */
58         private $groups = [];
59
60         /**
61          * Array with sub group
62          */
63         private $subGroups = [];
64
65         /**
66          * Previously opened group
67          */
68         private $previousGroupId = '';
69
70         /**
71          * Previously opened sub group
72          */
73         private $previousSubGroupId = '';
74
75         /**
76          * Total counter for groups and sub groups
77          */
78         private $totalCounter = 0;
79
80         // Exception constants
81         const EXCEPTION_GROUP_NOT_OPENED             = 0x1e0;
82         const EXCEPTION_SUB_GROUP_ALREADY_FOUND      = 0x1e1;
83         const EXCEPTION_NO_PREVIOUS_SUB_GROUP_OPENED = 0x1e2;
84         const EXCEPTION_NO_PREVIOUS_GROUP_OPENED     = 0x1e3;
85
86         /**
87          * Protected constructor
88          *
89          * @param       $className      Real name of the class
90          * @return      void
91          */
92         protected function __construct (string $className) {
93                 // Call parent constructor
94                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('BASE-HELPER: className=%s - CONSTRUCTED!', $className));
95                 parent::__construct($className);
96
97                 // Trace message
98                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage('BASE-HELPER: EXIT!');
99         }
100
101         /**
102          * Adds content directly
103          *
104          * @param       $newContent             New content to add
105          * @return      void
106          * @throws      InvalidArgumentException        If a parameter has an invalid value
107          */
108         protected final function addContent (string $newContent) {
109                 // Check variable
110                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('BASE-HELPER: newContent=%s - CALLED!', $newContent));
111                 if (empty(trim($newContent))) {
112                         // Throw IAE
113                         throw new InvalidArgumentException('Parameter "newContent" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
114                 }
115
116                 // Append content with EOL
117                 $this->content .= trim($newContent) . PHP_EOL;
118
119                 // Trace message
120                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('BASE-HELPER: this->content()=%d - EXIT!', strlen($this->content)));
121         }
122
123         /**
124          * Add header content to the helper
125          *
126          * @param       $content        Content to to the base
127          * @return      void
128          * @throws      InvalidArgumentException        If a parameter has an invalid value
129          */
130         protected function addHeaderContent (string $content) {
131                 // Check variable
132                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('BASE-HELPER: content=%s - CALLED!', $content));
133                 if (empty(trim($content))) {
134                         // Throw IAE
135                         throw new InvalidArgumentException('Parameter "content" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
136                 }
137
138                 // Add the header content
139                 $this->groups['header']['content'] = trim($content);
140
141                 // Trace message
142                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage('BASE-HELPER: EXIT!');
143         }
144
145         /**
146          * Add footer content to the helper
147          *
148          * @param       $content        Content to to the base
149          * @return      void
150          * @throws      InvalidArgumentException        If a parameter has an invalid value
151          */
152         protected function addFooterContent (string $content) {
153                 // Check variable
154                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('BASE-HELPER: content=%s - CALLED!', $content));
155                 if (empty(trim($content))) {
156                         // Throw IAE
157                         throw new InvalidArgumentException('Parameter "content" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
158                 }
159
160                 // Add the footer content
161                 $this->groups['footer']['content'] = trim($content);
162
163                 // Trace message
164                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage('BASE-HELPER: EXIT!');
165         }
166
167         /**
168          * Adds content to the previously opened group or sub group. If a sub group
169          * was found it will be taken. If no group/sub group is opened at the moment
170          * the code will be passed to addContent().
171          *
172          * @param       $newContent             New content to add
173          * @return      void
174          * @throws      InvalidArgumentException        If a parameter has an invalid value
175          */
176         protected final function addContentToPreviousGroup (string $newContent) {
177                 // Check on parameter
178                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: newContent=%s - CALLED!', $newContent));
179                 if (empty($newContent)) {
180                         // Throw IAE
181                         throw new InvalidArgumentException('Parameter "newContent" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
182                 }
183
184                 // Check for sub/group
185                 if ($this->ifSubGroupOpenedPreviously()) {
186                         // Get sub group id
187                         $subGroupId = $this->getPreviousSubGroupId();
188
189                         // Add the content
190                         $this->subGroups[$subGroupId]['content'] .= $newContent;
191                 } elseif ($this->ifGroupOpenedPreviously()) {
192                         // Get group id
193                         $groupId = $this->getPreviousGroupId();
194
195                         // Add the content
196                         $this->groups[$groupId]['content'] .= $newContent;
197                 } else {
198                         // Add it directly
199                         $this->addContent($newContent);
200                 }
201
202                 // Trace message
203                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-HELPER: EXIT!');
204         }
205
206         /**
207          * Getter for content
208          *
209          * @return      $content        The rendered content by this helper
210          */
211         protected final function getContent () {
212                 return $this->content;
213         }
214
215         /**
216          * Public setter for extra instance
217          *
218          * @param       $extraInstance  An extra instance of FrameworkInterface to set
219          * @return      void
220          */
221         public final function setExtraInstance (FrameworkInterface $extraInstance) {
222                 $this->extraInstance = $extraInstance;
223         }
224
225         /**
226          *  Assigns a field from the value instance with a template variable
227          *
228          * @param       $fieldName      Name of the field to assign
229          * @return      void
230          * @throws      InvalidArgumentException        If a parameter has an invalid value
231          */
232         public function assignField (string $fieldName) {
233                 // Check on parameter
234                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: fieldName=%s - CALLED!', $fieldName));
235                 if (empty($fieldName)) {
236                         // Throw IAE
237                         throw new InvalidArgumentException('Parameter "fieldName" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
238                 }
239
240                 // Get the value from value instance
241                 $fieldValue = $this->getValueField($fieldName);
242
243                 // Assign it with a template variable
244                 $this->getTemplateInstance()->assignVariable('block_' . $fieldName, $fieldValue);
245
246                 // Trace message
247                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-HELPER: EXIT!');
248         }
249
250         /**
251          * Assigns a field from the value instance with a template variable but
252          * parses its content through a given filter method of the value instance
253          *
254          * @param       $fieldName              Name of the field to assign
255          * @param       $filterMethod   Method name to call of the value instance
256          * @return      void
257          * @throws      InvalidArgumentException        If a parameter has an invalid value
258          * @todo        Rewrite this method using a helper class for filtering data
259          */
260         public function assignFieldWithFilter (string $fieldName, string $filterMethod) {
261                 // Validate parameter
262                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: fieldName=%s,filterMethod=%s - CALLED!', $fieldName, $filterMethod));
263                 if (empty($fieldName)) {
264                         // Throw IAE
265                         throw new InvalidArgumentException('Parameter "fieldName" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
266                 } elseif (empty($filterMethod)) {
267                         // Throw IAE
268                         throw new InvalidArgumentException('Parameter "filterMethod" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
269                 }
270
271                 // Get the value
272                 $fieldValue = $this->getValueField($fieldName);
273
274                 // Now filter it through the value through the filter method
275                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: %s[%s]=%s', $fieldName, gettype($fieldValue), $fieldValue));
276                 $filteredValue = call_user_func_array(array($this, 'doFilter' . StringUtils::convertToClassName($filterMethod)), array($fieldValue));
277
278                 // Assign it with a template variable
279                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: filteredValue[%s]=%s', gettype($filteredValue), $filteredValue));
280                 $this->getTemplateInstance()->assignVariable('block_' . $fieldName, $filteredValue);
281
282                 // Trace message
283                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-HELPER: EXIT!');
284         }
285
286         /**
287          * Pre-fetches field default values from the given registry key instance into this class
288          *
289          * @param       $registryKey    Registry key which holds an object with values
290          * @param       $extraKey               Extra value instance key used if registryKey is null
291          * @return      void
292          * @throws      InvalidArgumentException        If a parameter has an invalid value
293          */
294         public function prefetchValueInstance (string $registryKey, string $extraKey = NULL) {
295                 // Validate parameter
296                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: registryKey=%s,extraKey[%s]=%s - CALLED!', $registryKey, gettype($extraKey), $extraKey));
297                 if (empty($registryKey)) {
298                         // Throw IAE
299                         throw new InvalidArgumentException('Parameter "registryKey" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
300                 }
301
302                 try {
303                         // Get the required instance
304                         $this->valueInstance = ObjectRegistry::getRegistry('generic')->getInstance($registryKey);
305                 } catch (NullPointerException $e) {
306                         // Not set in registry
307                         //* DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: registryKey=%s returned no instance (NPE thrown)', $registryKey));
308                 }
309
310                 // Shall we get an extra instance?
311                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: extraKey[%s]=%s', gettype($extraKey), $extraKey));
312                 if (!is_null($extraKey)) {
313                         try {
314                                 // Get the extra instance.
315                                 $this->extraInstance = ObjectRegistry::getRegistry('generic')->getInstance($extraKey);
316                         } catch (NullPointerException $e) {
317                                 // Try to create it
318                                 //* DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: extraKey=%s returned no instance (NPE thrown), this->valueInstance[]=%s', $extraKey, gettype($this->valueInstance)));
319                                 $this->extraInstance = ObjectFactory::createObjectByConfiguredName($extraKey . '_class', [$this->valueInstance]);
320                         }
321                         //* DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: extraKey=%s,this->extraInstance[%s]=%s', $extraKey, gettype($this->extraInstance), $this->extraInstance));
322                 }
323
324                 // Is the value instance valid?
325                 //* NOSIY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: this->valueInstance[]=%s - BEFORE!', gettype($this->valueInstance)));
326                 if (is_null($this->valueInstance)) {
327                         // Get the requested instance
328                         $this->valueInstance = ObjectFactory::createObjectByConfiguredName($registryKey . '_class', array($this->extraInstance));
329                 }
330
331                 // Trace message
332                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: this->valueInstance[]=%s - AFTER/EXIT!', gettype($this->valueInstance)));
333         }
334
335         /**
336          * Opens a helper group with given group id and content or throws an
337          * exception if that group is already found regardless if it is open or
338          * closed.
339          *
340          * @param       $groupId        Group id to open
341          * @param       $content        Initial content to add to the group
342          * @param       $tag            HTML tag used to open this group
343          * @return      void
344          * @throws      InvalidArgumentException        If a parameter has an invalid value
345          * @throws      BadMethodCallException  If the group was already created before
346          */
347         protected function openGroupByIdContent (string $groupId, string $content, string $tag) {
348                 // Is the group already there?
349                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: groupdId=%s,content=%s,tag=%s - CALLED!', $groupdId, $content, $tag));
350                 if (empty($groupId)) {
351                         // Throw IAE
352                         throw new InvalidArgumentException('Parameter "groupId" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
353                 } elseif (isset($this->groups[$groupId])) {
354                         // Then throw an exception here
355                         throw new BadMethodCallException(sprintf('[%s:%d]: groupId=%s is already opened.', $this->__toString(), $groupId), FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
356                 } elseif (empty($content)) {
357                         // Throw IAE
358                         throw new InvalidArgumentException('Parameter "content" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
359                 } elseif (empty($tag)) {
360                         // Throw IAE
361                         throw new InvalidArgumentException('Parameter "tag" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
362                 }
363
364                 // Count one up
365                 $this->totalCounter++;
366
367                 // Add the group to the stack
368                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: this->totalCounter=%d', $this->totalCounter));
369                 $this->groups[$this->totalCounter] = $groupId;
370                 $this->groups[$groupId]['opened']  = true;
371                 $this->groups[$groupId]['content'] = sprintf(
372                         '<!-- group %s opened (length: %s, tag: %s) //-->%s' . PHP_EOL,
373                         $groupId,
374                         strlen($content),
375                         $tag,
376                         $content
377                 );
378                 $this->groups[$groupId]['tag'] = $tag;
379
380                 // Mark this group as previously opened
381                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: Setting this->previousGroupId=%s ...', $groupId));
382                 $this->setPreviousGroupId($groupId);
383
384                 // Trace message
385                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-HELPER: EXIT!');
386         }
387
388         /**
389          * Closes the previously opened group by added given content to it or
390          * throws an exception if no previous group was opened
391          *
392          * @param       $content        Content for previously opened group, or empty to use tag of opener
393          * @return      void
394          * @throws      HelperNoPreviousOpenedGroupException    If no previously opened group was found
395          */
396         public function closePreviousGroupByContent (string $content = '') {
397                 // Check if any sub group was opened before
398                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: content(%d)=%s - CALLED!', strlen($content), $content));
399                 if ($this->ifSubGroupOpenedPreviously()) {
400                         // Close it automatically
401                         $this->closePreviousSubGroupByContent();
402                 }
403
404                 // Check if any group was opened before
405                 if ($this->ifGroupOpenedPreviously() === false) {
406                         // Then throw an exception
407                         throw new HelperNoPreviousOpenedGroupException(array($this, $content), self::EXCEPTION_NO_PREVIOUS_SUB_GROUP_OPENED);
408                 }
409
410                 // Get previous group
411                 $groupId = $this->getPreviousGroupId();
412
413                 // Is the content empty?
414                 if ((empty($content)) && (!empty($this->groups[$groupId]['tag']))) {
415                         // Get it from opener
416                         $content = sprintf(
417                                 "<!-- group %s auto-closed //--></%s>",
418                                 $groupId,
419                                 $this->groups[$groupId]['tag']
420                         );
421                 }
422
423                 // Add content to it and mark it as closed
424                 $this->groups[$groupId]['content'] .= sprintf(
425                         "<!-- group %s closed (length: %s, tag: %s) //-->%s\n",
426                         $groupId,
427                         strlen($content),
428                         $this->groups[$groupId]['tag'],
429                         $content
430                 );
431                 $this->groups[$groupId]['opened'] = false;
432
433                 // Mark previous group as closed
434                 $this->setPreviousGroupId('');
435                 //* NOISY-DEBUG: */ echo "CLOSE:groupId={$groupId}<br />\n";
436         }
437
438         /**
439          * Opens a helper sub group with given group id and content or throws an
440          * exception if that sub group is already found regardless if it is open or
441          * closed.
442          *
443          * @param       $subGroupId             Sub group id to open
444          * @param       $content                Initial content to add to the sub group
445          * @param       $tag                    HTML tag used to open this group
446          * @return      void
447          * @throws      HelperSubGroupAlreadyCreatedException   If the sub group was already created before
448          */
449         protected function openSubGroupByIdContent (string $subGroupId, string $content, string $tag) {
450                 //* NOISY-DEBUG: */ echo "OPEN:subGroupId={$subGroupId},content=".htmlentities($content)."<br />\n";
451                 // Is the group already there?
452                 if (empty($subGroupId)) {
453                         // Throw IAE
454                         throw new InvalidArgumentException('Parameter "subGroupId" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
455                 } elseif (isset($this->subGroups[$subGroupId])) {
456                         // Then throw an exception here
457                         throw new HelperSubGroupAlreadyCreatedException(array($this, $subGroupId), self::EXCEPTION_SUB_GROUP_ALREADY_FOUND);
458                 }
459
460                 // Count one up
461                 $this->totalCounter++;
462
463                 // Add the group to the stack
464                 $this->subGroups[$this->totalCounter] = $subGroupId;
465                 $this->subGroups[$subGroupId]['opened']  = true;
466                 $this->subGroups[$subGroupId]['content'] = sprintf("<!-- sub-group %s opened (length: %s, tag: %s) //-->%s\n", $subGroupId, strlen($content), $tag, $content);
467                 $this->subGroups[$subGroupId]['tag'] = $tag;
468
469                 // Mark this group as previously opened
470                 $this->setPreviousSubGroupId($subGroupId);
471         }
472
473         /**
474          * Closes the previously opened sub group by added given content to it or
475          * throws an exception if no previous sub group was opened
476          *
477          * @param       $content        Content for previously opened sub group, or leave empty to use div/span of openener
478          * @return      void
479          * @throws      HelperNoPreviousOpenedSubGroupException If no previously opened sub group was found
480          */
481         public function closePreviousSubGroupByContent (string $content = '') {
482                 // Check if any sub group was opened before
483                 if ($this->ifSubGroupOpenedPreviously() === false) {
484                         // Then throw an exception
485                         throw new HelperNoPreviousOpenedSubGroupException(array($this, $content), self::EXCEPTION_NO_PREVIOUS_SUB_GROUP_OPENED);
486                 }
487
488                 // Get previous sub group
489                 $subGroupId = $this->getPreviousSubGroupId();
490
491                 // Is the content empty?
492                 if ((empty($content)) && (!empty($this->subGroups[$subGroupId]['tag']))) {
493                         // Get it from opener
494                         $content = sprintf('<!-- sub-group %s auto-closed //--></%s>', $subGroupId, $this->subGroups[$subGroupId]['tag']);
495                 }
496
497                 // Add content to it and mark it as closed
498                 $this->subGroups[$subGroupId]['content'] .= sprintf('<!-- sub-group %s closed (length: %s, tag: %s) //-->%s' . PHP_EOL, $subGroupId, strlen($content), $this->subGroups[$subGroupId]['tag'], $content);
499                 $this->subGroups[$subGroupId]['opened'] = false
500                 ;
501
502                 // Mark previous sub group as closed
503                 $this->setPreviousSubGroupId('');
504                 //* NOISY-DEBUG: */ echo "CLOSE:subGroupId={$subGroupId}<br />\n";
505         }
506
507         /**
508          * Renders all group and sub group in their order
509          *
510          * @return      $content        Rendered HTML content
511          */
512         public function renderContent () {
513                 // Initialize content
514                 $content = '';
515
516                 // Is header content there?
517                 if (isset($this->groups['header'])) {
518                         // Then add it
519                         $content .= $this->groups['header']['content'] . PHP_EOL;
520                 }
521
522                 // Initiate content
523                 $content .= $this->getContent();
524
525                 // Now "walk" through all groups and sub-groups
526                 for ($idx = 1; $idx <= $this->totalCounter; $idx++) {
527                         // Is this a sub/group and is it closed?
528                         if ((isset($this->groups[$idx])) && ($this->groups[$this->groups[$idx]]['opened'] === false)) {
529                                 // Then add it's content
530                                 $groupContent = trim($this->groups[$this->groups[$idx]]['content']);
531                                 //* NOISY-DEBUG: */ echo "group={$this->groups[$idx]},content=<pre>".htmlentities($groupContent)."</pre><br />\n";
532                                 $content .= $groupContent;
533                         } elseif ((isset($this->subGroups[$idx])) && ($this->subGroups[$this->subGroups[$idx]]['opened'] === false)) {
534                                 // Then add it's content
535                                 $subGroupContent = $this->subGroups[$this->subGroups[$idx]]['content'];
536                                 //* NOISY-DEBUG: */ echo "subgroup={$this->subGroups[$idx]},content=<pre>".htmlentities($subGroupContent)."</pre><br />\n";
537                                 $content .= trim($subGroupContent);
538                         } else {
539                                 // Something went wrong
540                                 $this->debugInstance(__METHOD__ . '(): Something unexpected happened here.');
541                         }
542                 }
543
544                 // Is footer content there?
545                 if (isset($this->groups['footer'])) {
546                         // Then add it
547                         $content .= $this->groups['footer']['content'] . PHP_EOL;
548                 }
549
550                 // Return it
551                 //* NOISY-DEBUG: */ echo "content=<pre>".htmlentities($content)."</pre> (".strlen($content).")<br />\n";
552                 return $content;
553         }
554
555         /**
556          * Checks whether the specified group is opened
557          *
558          * @param       $groupId        Id of group to check
559          * @return      $isOpened       Whether the specified group is open
560          * @throws      InvalidArgumentException        If a parameter has an invalid value
561          */
562         protected function ifGroupIsOpened (string $groupId) {
563                 // Check on parameter
564                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: groupId=%s - CALLED!', $groupId));
565                 if (empty($groupId)) {
566                         // Throw IAE
567                         throw new InvalidArgumentException('Parameter "groupId" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
568                 }
569
570                 // Is the group open?
571                 $isOpened = ((isset($this->groups[$groupId])) && ($this->groups[$groupId]['opened'] === true));
572
573                 // Return status
574                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: isOpened=%d - EXIT!', intval($isOpened)));
575                 return $isOpened;
576         }
577
578         /**
579          * Getter for direct field values
580          *
581          * @param       $fieldName              Name of the field we shall fetch
582          * @return      $fieldValue             Value from field
583          * @throws      InvalidArgumentException        If a parameter has an invalid value
584          * @throws      NullPointerException    Thrown if $valueInstance is null
585          */
586         public function getValueField (string $fieldName) {
587                 // Check parameter
588                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: fieldName=%s - CALLED!', $fieldName));
589                 if (empty($fieldName)) {
590                         // Throw IAE
591                         throw new InvalidArgumentException('Parameter "fieldName" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
592                 }
593
594                 // Init value
595                 $fieldValue = NULL;
596
597                 // The $valueInstance attribute should not be null!
598                 if (is_null($this->getValueInstance())) {
599                         // Throws an exception here
600                         throw new NullPointerException($this, FrameworkInterface::EXCEPTION_IS_NULL_POINTER);
601                 }
602
603                 // Is the field set?
604                 if ($this->getValueInstance()->isFieldSet($fieldName)) {
605                         // Get the field value
606                         $fieldValue = $this->getValueInstance()->getField($fieldName);
607                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput($fieldName.'[]='.gettype($fieldValue).'('.strlen($fieldValue).') - Value instance!');
608                 } elseif ((!is_null($this->extraInstance)) && ($this->extraInstance->isFieldSet($fieldName))) {
609                         // So try the extra instance
610                         $fieldValue = $this->extraInstance->getField($fieldName);
611                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput($fieldName.'[]='.gettype($fieldValue).'('.strlen($fieldValue).') - Extra instance!');
612                 } else {
613                         // Field is not set
614                         $this->debugOutput('BASE-HELPER: fieldName=' . $fieldName . ' is not set! - @TODO');
615                 }
616
617                 // Return it
618                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: fieldValue[%s]=%s - EXIT!', gettype($fieldValue), $fieldValue));
619                 return $fieldValue;
620         }
621
622         /**
623          * Getter for value instance
624          *
625          * @return      $valueInstance  Instance of the class holding our values
626          */
627         public final function getValueInstance () {
628                 return $this->valueInstance;
629         }
630
631         /**
632          * Check whether a group was opened previously
633          *
634          * @return      $groupOpened    Whether any group was opened before
635          */
636         protected final function ifGroupOpenedPreviously () {
637                 $groupOpened = (!empty($this->previousGroupId));
638                 return $groupOpened;
639         }
640
641         /**
642          * Check whether a group was opened previously
643          *
644          * @return      $subGroupOpened         Whether any group was opened before
645          */
646         protected final function ifSubGroupOpenedPreviously () {
647                 $subGroupOpened = (!empty($this->previousSubGroupId));
648                 return $subGroupOpened;
649         }
650
651         /**
652          * Getter for previous group id
653          *
654          * @return      $previousGroupId        Id of previously opened group
655          */
656         protected final function getPreviousGroupId () {
657                 return $this->previousGroupId;
658         }
659
660         /**
661          * Setter for previous group id
662          *
663          * @param       $previousGroupId        Id of previously opened group
664          * @return      void
665          */
666         protected final function setPreviousGroupId (string $previousGroupId) {
667                 $this->previousGroupId = $previousGroupId;
668         }
669
670         /**
671          * Getter for previous sub group id
672          *
673          * @return      $previousSubGroupId             Id of previously opened sub group
674          */
675         protected final function getPreviousSubGroupId () {
676                 return $this->previousSubGroupId;
677         }
678
679         /**
680          * Setter for previous sub group id
681          *
682          * @param       $previousSubGroupId             Id of previously opened sub group
683          * @return      void
684          */
685         protected final function setPreviousSubGroupId (string $previousSubGroupId) {
686                 $this->previousSubGroupId = $previousSubGroupId;
687         }
688
689 }