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