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