]> 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\GenericRegistry;
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 - 2022 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             = 0x1e3;
82         const EXCEPTION_GROUP_ALREADY_FOUND          = 0x1e4;
83         const EXCEPTION_SUB_GROUP_ALREADY_FOUND      = 0x1e5;
84         const EXCEPTION_NO_PREVIOUS_SUB_GROUP_OPENED = 0x1e6;
85         const EXCEPTION_NO_PREVIOUS_GROUP_OPENED     = 0x1e7;
86
87         /**
88          * Protected constructor
89          *
90          * @param       $className      Real name of the class
91          * @return      void
92          */
93         protected function __construct (string $className) {
94                 // Call parent constructor
95                 parent::__construct($className);
96         }
97
98         /**
99          * Adds content directly
100          *
101          * @param       $newContent             New content to add
102          * @return      void
103          */
104         protected final function addContent (string $newContent) {
105                 $this->content .= trim($newContent) . PHP_EOL;
106         }
107
108         /**
109          * Add header content to the helper
110          *
111          * @param       $content        Content to to the base
112          * @return      void
113          */
114         protected function addHeaderContent (string $content) {
115                 // Add the header content
116                 $this->groups['header']['content'] = trim($content);
117         }
118
119         /**
120          * Add footer content to the helper
121          *
122          * @param       $content        Content to to the base
123          * @return      void
124          */
125         protected function addFooterContent (string $content) {
126                 // Add the footer content
127                 $this->groups['footer']['content'] = trim($content);
128         }
129
130         /**
131          * Adds content to the previously opened group or sub group. If a sub group
132          * was found it will be taken. If no group/sub group is opened at the moment
133          * the code will be passed to addContent().
134          *
135          * @param       $newContent             New content to add
136          * @return      void
137          * @throws      InvalidArgumentException        If a parameter has an invalid value
138          */
139         protected final function addContentToPreviousGroup (string $newContent) {
140                 // Check on parameter
141                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: newContent=%s - CALLED!', $newContent));
142                 if (empty($newContent)) {
143                         // Throw IAE
144                         throw new InvalidArgumentException('Parameter "newContent" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
145                 }
146
147                 // Check for sub/group
148                 if ($this->ifSubGroupOpenedPreviously()) {
149                         // Get sub group id
150                         $subGroupId = $this->getPreviousSubGroupId();
151
152                         // Add the content
153                         $this->subGroups[$subGroupId]['content'] .= $newContent;
154                 } elseif ($this->ifGroupOpenedPreviously()) {
155                         // Get group id
156                         $groupId = $this->getPreviousGroupId();
157
158                         // Add the content
159                         $this->groups[$groupId]['content'] .= $newContent;
160                 } else {
161                         // Add it directly
162                         $this->addContent($newContent);
163                 }
164
165                 // Trace message
166                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-HELPER: EXIT!');
167         }
168
169         /**
170          * Getter for content
171          *
172          * @return      $content        The rendered content by this helper
173          */
174         protected final function getContent () {
175                 return $this->content;
176         }
177
178         /**
179          * Public setter for extra instance
180          *
181          * @param       $extraInstance  An extra instance of FrameworkInterface to set
182          * @return      void
183          */
184         public final function setExtraInstance (FrameworkInterface $extraInstance) {
185                 $this->extraInstance = $extraInstance;
186         }
187
188         /**
189          *  Assigns a field from the value instance with a template variable
190          *
191          * @param       $fieldName      Name of the field to assign
192          * @return      void
193          * @throws      InvalidArgumentException        If a parameter has an invalid value
194          */
195         public function assignField (string $fieldName) {
196                 // Check on parameter
197                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: fieldName=%s - CALLED!', $fieldName));
198                 if (empty($fieldName)) {
199                         // Throw IAE
200                         throw new InvalidArgumentException('Parameter "fieldName" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
201                 }
202
203                 // Get the value from value instance
204                 $fieldValue = $this->getValueField($fieldName);
205
206                 // Assign it with a template variable
207                 $this->getTemplateInstance()->assignVariable('block_' . $fieldName, $fieldValue);
208
209                 // Trace message
210                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-HELPER: EXIT!');
211         }
212
213         /**
214          * Assigns a field from the value instance with a template variable but
215          * parses its content through a given filter method of the value instance
216          *
217          * @param       $fieldName              Name of the field to assign
218          * @param       $filterMethod   Method name to call of the value instance
219          * @return      void
220          * @throws      InvalidArgumentException        If a parameter has an invalid value
221          * @todo        Rewrite this method using a helper class for filtering data
222          */
223         public function assignFieldWithFilter (string $fieldName, string $filterMethod) {
224                 // Validate parameter
225                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: fieldName=%s,filterMethod=%s - CALLED!', $fieldName, $filterMethod));
226                 if (empty($fieldName)) {
227                         // Throw IAE
228                         throw new InvalidArgumentException('Parameter "fieldName" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
229                 } elseif (empty($filterMethod)) {
230                         // Throw IAE
231                         throw new InvalidArgumentException('Parameter "filterMethod" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
232                 }
233
234                 // Get the value
235                 $fieldValue = $this->getValueField($fieldName);
236
237                 // Now filter it through the value through the filter method
238                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: %s[%s]=%s', $fieldName, gettype($fieldValue), $fieldValue));
239                 $filteredValue = call_user_func_array(array($this, 'doFilter' . StringUtils::convertToClassName($filterMethod)), array($fieldValue));
240
241                 // Assign it with a template variable
242                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: filteredValue[%s]=%s', gettype($filteredValue), $filteredValue));
243                 $this->getTemplateInstance()->assignVariable('block_' . $fieldName, $filteredValue);
244
245                 // Trace message
246                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-HELPER: EXIT!');
247         }
248
249         /**
250          * Pre-fetches field default values from the given registry key instance into this class
251          *
252          * @param       $registryKey    Registry key which holds an object with values
253          * @param       $extraKey               Extra value instance key used if registryKey is null
254          * @return      void
255          * @throws      InvalidArgumentException        If a parameter has an invalid value
256          */
257         public function prefetchValueInstance (string $registryKey, string $extraKey = NULL) {
258                 // Validate parameter
259                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: registryKey=%s,extraKey[%s]=%s - CALLED!', $registryKey, gettype($extraKey), $extraKey));
260                 if (empty($registryKey)) {
261                         // Throw IAE
262                         throw new InvalidArgumentException('Parameter "registryKey" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
263                 }
264
265                 try {
266                         // Get the required instance
267                         $this->valueInstance = GenericRegistry::getRegistry()->getInstance($registryKey);
268                 } catch (NullPointerException $e) {
269                         // Not set in registry
270                         //* DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: registryKey=%s returned no instance (NPE thrown)', $registryKey));
271                 }
272
273                 // Shall we get an extra instance?
274                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: extraKey[%s]=%s', gettype($extraKey), $extraKey));
275                 if (!is_null($extraKey)) {
276                         try {
277                                 // Get the extra instance.
278                                 $this->extraInstance = GenericRegistry::getRegistry()->getInstance($extraKey);
279                         } catch (NullPointerException $e) {
280                                 // Try to create it
281                                 //* DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: extraKey=%s returned no instance (NPE thrown), this->valueInstance[]=%s', $extraKey, gettype($this->valueInstance)));
282                                 $this->extraInstance = ObjectFactory::createObjectByConfiguredName($extraKey . '_class', [$this->valueInstance]);
283                         }
284                         //* DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: extraKey=%s,this->extraInstance[%s]=%s', $extraKey, gettype($this->extraInstance), $this->extraInstance));
285                 }
286
287                 // Is the value instance valid?
288                 //* NOSIY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: this->valueInstance[]=%s - BEFORE!', gettype($this->valueInstance)));
289                 if (is_null($this->valueInstance)) {
290                         // Get the requested instance
291                         $this->valueInstance = ObjectFactory::createObjectByConfiguredName($registryKey . '_class', array($this->extraInstance));
292                 }
293
294                 // Trace message
295                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: this->valueInstance[]=%s - AFTER/EXIT!', gettype($this->valueInstance)));
296         }
297
298         /**
299          * Opens a helper group with given group id and content or throws an
300          * exception if that group is already found regardless if it is open or
301          * closed.
302          *
303          * @param       $groupId        Group id to open
304          * @param       $content        Initial content to add to the group
305          * @param       $tag            HTML tag used to open this group
306          * @return      void
307          * @throws      InvalidArgumentException        If a parameter has an invalid value
308          * @throws      BadMethodCallException  If the group was already created before
309          */
310         protected function openGroupByIdContent (string $groupId, string $content, string $tag) {
311                 // Is the group already there?
312                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: groupdId=%s,content=%s,tag=%s - CALLED!', $groupdId, $content, $tag));
313                 if (empty($groupId)) {
314                         // Throw IAE
315                         throw new InvalidArgumentException('Parameter "groupId" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
316                 } elseif (isset($this->groups[$groupId])) {
317                         // Then throw an exception here
318                         throw new BadMethodCallException(sprintf('[%s:%d]: groupId=%s is already opened.', $this->__toString(), $groupId), self::EXCEPTION_GROUP_ALREADY_FOUND);
319                 } elseif (empty($content)) {
320                         // Throw IAE
321                         throw new InvalidArgumentException('Parameter "content" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
322                 } elseif (empty($tag)) {
323                         // Throw IAE
324                         throw new InvalidArgumentException('Parameter "tag" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
325                 }
326
327                 // Count one up
328                 $this->totalCounter++;
329
330                 // Add the group to the stack
331                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: this->totalCounter=%d', $this->totalCounter));
332                 $this->groups[$this->totalCounter] = $groupId;
333                 $this->groups[$groupId]['opened']  = true;
334                 $this->groups[$groupId]['content'] = sprintf(
335                         '<!-- group %s opened (length: %s, tag: %s) //-->%s' . PHP_EOL,
336                         $groupId,
337                         strlen($content),
338                         $tag,
339                         $content
340                 );
341                 $this->groups[$groupId]['tag'] = $tag;
342
343                 // Mark this group as previously opened
344                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: Setting this->previousGroupId=%s ...', $groupId));
345                 $this->setPreviousGroupId($groupId);
346
347                 // Trace message
348                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-HELPER: EXIT!');
349         }
350
351         /**
352          * Closes the previously opened group by added given content to it or
353          * throws an exception if no previous group was opened
354          *
355          * @param       $content        Content for previously opened group, or empty to use tag of opener
356          * @return      void
357          * @throws      HelperNoPreviousOpenedGroupException    If no previously opened group was found
358          */
359         public function closePreviousGroupByContent (string $content = '') {
360                 // Check if any sub group was opened before
361                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: content(%d)=%s - CALLED!', strlen($content), $content));
362                 if ($this->ifSubGroupOpenedPreviously()) {
363                         // Close it automatically
364                         $this->closePreviousSubGroupByContent();
365                 }
366
367                 // Check if any group was opened before
368                 if ($this->ifGroupOpenedPreviously() === false) {
369                         // Then throw an exception
370                         throw new HelperNoPreviousOpenedGroupException(array($this, $content), self::EXCEPTION_NO_PREVIOUS_SUB_GROUP_OPENED);
371                 }
372
373                 // Get previous group
374                 $groupId = $this->getPreviousGroupId();
375
376                 // Is the content empty?
377                 if ((empty($content)) && (!empty($this->groups[$groupId]['tag']))) {
378                         // Get it from opener
379                         $content = sprintf(
380                                 "<!-- group %s auto-closed //--></%s>",
381                                 $groupId,
382                                 $this->groups[$groupId]['tag']
383                         );
384                 }
385
386                 // Add content to it and mark it as closed
387                 $this->groups[$groupId]['content'] .= sprintf(
388                         "<!-- group %s closed (length: %s, tag: %s) //-->%s\n",
389                         $groupId,
390                         strlen($content),
391                         $this->groups[$groupId]['tag'],
392                         $content
393                 );
394                 $this->groups[$groupId]['opened'] = false;
395
396                 // Mark previous group as closed
397                 $this->setPreviousGroupId('');
398                 //* NOISY-DEBUG: */ echo "CLOSE:groupId={$groupId}<br />\n";
399         }
400
401         /**
402          * Opens a helper sub group with given group id and content or throws an
403          * exception if that sub group is already found regardless if it is open or
404          * closed.
405          *
406          * @param       $subGroupId             Sub group id to open
407          * @param       $content                Initial content to add to the sub group
408          * @param       $tag                    HTML tag used to open this group
409          * @return      void
410          * @throws      HelperSubGroupAlreadyCreatedException   If the sub group was already created before
411          */
412         protected function openSubGroupByIdContent (string $subGroupId, string $content, string $tag) {
413                 //* NOISY-DEBUG: */ echo "OPEN:subGroupId={$subGroupId},content=".htmlentities($content)."<br />\n";
414                 // Is the group already there?
415                 if (empty($subGroupId)) {
416                         // Throw IAE
417                         throw new InvalidArgumentException('Parameter "subGroupId" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
418                 } elseif (isset($this->subGroups[$subGroupId])) {
419                         // Then throw an exception here
420                         throw new HelperSubGroupAlreadyCreatedException(array($this, $subGroupId), self::EXCEPTION_SUB_GROUP_ALREADY_FOUND);
421                 }
422
423                 // Count one up
424                 $this->totalCounter++;
425
426                 // Add the group to the stack
427                 $this->subGroups[$this->totalCounter] = $subGroupId;
428                 $this->subGroups[$subGroupId]['opened']  = true;
429                 $this->subGroups[$subGroupId]['content'] = sprintf("<!-- sub-group %s opened (length: %s, tag: %s) //-->%s\n", $subGroupId, strlen($content), $tag, $content);
430                 $this->subGroups[$subGroupId]['tag'] = $tag;
431
432                 // Mark this group as previously opened
433                 $this->setPreviousSubGroupId($subGroupId);
434         }
435
436         /**
437          * Closes the previously opened sub group by added given content to it or
438          * throws an exception if no previous sub group was opened
439          *
440          * @param       $content        Content for previously opened sub group, or leave empty to use div/span of openener
441          * @return      void
442          * @throws      HelperNoPreviousOpenedSubGroupException If no previously opened sub group was found
443          */
444         public function closePreviousSubGroupByContent (string $content = '') {
445                 // Check if any sub group was opened before
446                 if ($this->ifSubGroupOpenedPreviously() === false) {
447                         // Then throw an exception
448                         throw new HelperNoPreviousOpenedSubGroupException(array($this, $content), self::EXCEPTION_NO_PREVIOUS_SUB_GROUP_OPENED);
449                 }
450
451                 // Get previous sub group
452                 $subGroupId = $this->getPreviousSubGroupId();
453
454                 // Is the content empty?
455                 if ((empty($content)) && (!empty($this->subGroups[$subGroupId]['tag']))) {
456                         // Get it from opener
457                         $content = sprintf('<!-- sub-group %s auto-closed //--></%s>', $subGroupId, $this->subGroups[$subGroupId]['tag']);
458                 }
459
460                 // Add content to it and mark it as closed
461                 $this->subGroups[$subGroupId]['content'] .= sprintf('<!-- sub-group %s closed (length: %s, tag: %s) //-->%s' . PHP_EOL, $subGroupId, strlen($content), $this->subGroups[$subGroupId]['tag'], $content);
462                 $this->subGroups[$subGroupId]['opened'] = false
463                 ;
464
465                 // Mark previous sub group as closed
466                 $this->setPreviousSubGroupId('');
467                 //* NOISY-DEBUG: */ echo "CLOSE:subGroupId={$subGroupId}<br />\n";
468         }
469
470         /**
471          * Renders all group and sub group in their order
472          *
473          * @return      $content        Rendered HTML content
474          */
475         public function renderContent () {
476                 // Initialize content
477                 $content = '';
478
479                 // Is header content there?
480                 if (isset($this->groups['header'])) {
481                         // Then add it
482                         $content .= $this->groups['header']['content'] . PHP_EOL;
483                 }
484
485                 // Initiate content
486                 $content .= $this->getContent();
487
488                 // Now "walk" through all groups and sub-groups
489                 for ($idx = 1; $idx <= $this->totalCounter; $idx++) {
490                         // Is this a sub/group and is it closed?
491                         if ((isset($this->groups[$idx])) && ($this->groups[$this->groups[$idx]]['opened'] === false)) {
492                                 // Then add it's content
493                                 $groupContent = trim($this->groups[$this->groups[$idx]]['content']);
494                                 //* NOISY-DEBUG: */ echo "group={$this->groups[$idx]},content=<pre>".htmlentities($groupContent)."</pre><br />\n";
495                                 $content .= $groupContent;
496                         } elseif ((isset($this->subGroups[$idx])) && ($this->subGroups[$this->subGroups[$idx]]['opened'] === false)) {
497                                 // Then add it's content
498                                 $subGroupContent = $this->subGroups[$this->subGroups[$idx]]['content'];
499                                 //* NOISY-DEBUG: */ echo "subgroup={$this->subGroups[$idx]},content=<pre>".htmlentities($subGroupContent)."</pre><br />\n";
500                                 $content .= trim($subGroupContent);
501                         } else {
502                                 // Something went wrong
503                                 $this->debugInstance(__METHOD__ . '(): Something unexpected happened here.');
504                         }
505                 }
506
507                 // Is footer content there?
508                 if (isset($this->groups['footer'])) {
509                         // Then add it
510                         $content .= $this->groups['footer']['content'] . PHP_EOL;
511                 }
512
513                 // Return it
514                 //* NOISY-DEBUG: */ echo "content=<pre>".htmlentities($content)."</pre> (".strlen($content).")<br />\n";
515                 return $content;
516         }
517
518         /**
519          * Checks whether the specified group is opened
520          *
521          * @param       $groupId        Id of group to check
522          * @return      $isOpened       Whether the specified group is open
523          * @throws      InvalidArgumentException        If a parameter has an invalid value
524          */
525         protected function ifGroupIsOpened (string $groupId) {
526                 // Check on parameter
527                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: groupId=%s - CALLED!', $groupId));
528                 if (empty($groupId)) {
529                         // Throw IAE
530                         throw new InvalidArgumentException('Parameter "groupId" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
531                 }
532
533                 // Is the group open?
534                 $isOpened = ((isset($this->groups[$groupId])) && ($this->groups[$groupId]['opened'] === true));
535
536                 // Return status
537                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: isOpened=%d - EXIT!', intval($isOpened)));
538                 return $isOpened;
539         }
540
541         /**
542          * Getter for direct field values
543          *
544          * @param       $fieldName              Name of the field we shall fetch
545          * @return      $fieldValue             Value from field
546          * @throws      InvalidArgumentException        If a parameter has an invalid value
547          * @throws      NullPointerException    Thrown if $valueInstance is null
548          */
549         public function getValueField (string $fieldName) {
550                 // Check parameter
551                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: fieldName=%s - CALLED!', $fieldName));
552                 if (empty($fieldName)) {
553                         // Throw IAE
554                         throw new InvalidArgumentException('Parameter "fieldName" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
555                 }
556
557                 // Init value
558                 $fieldValue = NULL;
559
560                 // The $valueInstance attribute should not be null!
561                 if (is_null($this->getValueInstance())) {
562                         // Throws an exception here
563                         throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
564                 }
565
566                 // Is the field set?
567                 if ($this->getValueInstance()->isFieldSet($fieldName)) {
568                         // Get the field value
569                         $fieldValue = $this->getValueInstance()->getField($fieldName);
570                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput($fieldName.'[]='.gettype($fieldValue).'('.strlen($fieldValue).') - Value instance!');
571                 } elseif ((!is_null($this->extraInstance)) && ($this->extraInstance->isFieldSet($fieldName))) {
572                         // So try the extra instance
573                         $fieldValue = $this->extraInstance->getField($fieldName);
574                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput($fieldName.'[]='.gettype($fieldValue).'('.strlen($fieldValue).') - Extra instance!');
575                 } else {
576                         // Field is not set
577                         $this->debugOutput('BASE-HELPER: fieldName=' . $fieldName . ' is not set! - @TODO');
578                 }
579
580                 // Return it
581                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-HELPER: fieldValue[%s]=%s - EXIT!', gettype($fieldValue), $fieldValue));
582                 return $fieldValue;
583         }
584
585         /**
586          * Getter for value instance
587          *
588          * @return      $valueInstance  Instance of the class holding our values
589          */
590         public final function getValueInstance () {
591                 return $this->valueInstance;
592         }
593
594         /**
595          * Check whether a group was opened previously
596          *
597          * @return      $groupOpened    Whether any group was opened before
598          */
599         protected final function ifGroupOpenedPreviously () {
600                 $groupOpened = (!empty($this->previousGroupId));
601                 return $groupOpened;
602         }
603
604         /**
605          * Check whether a group was opened previously
606          *
607          * @return      $subGroupOpened         Whether any group was opened before
608          */
609         protected final function ifSubGroupOpenedPreviously () {
610                 $subGroupOpened = (!empty($this->previousSubGroupId));
611                 return $subGroupOpened;
612         }
613
614         /**
615          * Getter for previous group id
616          *
617          * @return      $previousGroupId        Id of previously opened group
618          */
619         protected final function getPreviousGroupId () {
620                 return $this->previousGroupId;
621         }
622
623         /**
624          * Setter for previous group id
625          *
626          * @param       $previousGroupId        Id of previously opened group
627          * @return      void
628          */
629         protected final function setPreviousGroupId (string $previousGroupId) {
630                 $this->previousGroupId = $previousGroupId;
631         }
632
633         /**
634          * Getter for previous sub group id
635          *
636          * @return      $previousSubGroupId             Id of previously opened sub group
637          */
638         protected final function getPreviousSubGroupId () {
639                 return $this->previousSubGroupId;
640         }
641
642         /**
643          * Setter for previous sub group id
644          *
645          * @param       $previousSubGroupId             Id of previously opened sub group
646          * @return      void
647          */
648         protected final function setPreviousSubGroupId (string $previousSubGroupId) {
649                 $this->previousSubGroupId = $previousSubGroupId;
650         }
651
652 }