f0d436f0fa8bf25518f44b2559c3daeae278d651
[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          * Public setter for extra instance
154          *
155          * @param       $extraInstance  An extra instance of FrameworkInterface to set
156          * @return      void
157          */
158         public final function setExtraInstance (FrameworkInterface $extraInstance) {
159                 $this->extraInstance = $extraInstance;
160         }
161
162         /**
163          *  Assigns a field from the value instance with a template variable
164          *
165          * @param       $fieldName      Name of the field to assign
166          * @return      void
167          */
168         public function assignField ($fieldName) {
169                 // Get the value from value instance
170                 $fieldValue = $this->getValueField($fieldName);
171
172                 // Assign it with a template variable
173                 $this->getTemplateInstance()->assignVariable('block_' . $fieldName, $fieldValue);
174         }
175
176         /**
177          * Assigns a field from the value instance with a template variable but
178          * parses its content through a given filter method of the value instance
179          *
180          * @param       $fieldName              Name of the field to assign
181          * @param       $filterMethod   Method name to call of the value instance
182          * @return      void
183          * @todo        Rewrite this method using a helper class for filtering data
184          */
185         public function assignFieldWithFilter ($fieldName, $filterMethod) {
186                 // Get the value
187                 $fieldValue = $this->getValueField($fieldName);
188                 //* DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput($fieldName.'='.$fieldValue);
189
190                 // Now filter it through the value through the filter method
191                 $filteredValue = call_user_func_array(array($this, 'doFilter' . $this->convertToClassName($filterMethod)), array($fieldValue));
192
193                 // Assign it with a template variable
194                 $this->getTemplateInstance()->assignVariable('block_' . $fieldName, $filteredValue);
195         }
196
197         /**
198          * Pre-fetches field default values from the given registry key instance into this class
199          *
200          * @param       $registryKey    Registry key which holds an object with values
201          * @param       $extraKey               Extra value instance key used if registryKey is null
202          * @return      void
203          * @throws      NullPointerException    If recovery of requested value instance failed
204          */
205         public function prefetchValueInstance ($registryKey, $extraKey = NULL) {
206                 //* DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('O:'.$registryKey.'/'.$extraKey);
207                 try {
208                         // Get the required instance
209                         $this->valueInstance = Registry::getRegistry()->getInstance($registryKey);
210                 } catch (NullPointerException $e) {
211                         // Not set in registry
212                         // @TODO Try to log it here
213                         //* DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput($registryKey.'=NULL!');
214                 }
215
216                 // Shall we get an extra instance?
217                 if (!is_null($extraKey)) {
218                         try {
219                                 // Get the extra instance.
220                                 $this->extraInstance = Registry::getRegistry()->getInstance($extraKey);
221                         } catch (NullPointerException $e) {
222                                 // Try to create it
223                                 $this->extraInstance = ObjectFactory::createObjectByConfiguredName($extraKey . '_class', array($this->valueInstance));
224                         }
225                         //* DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput($extraKey.'='.$this->extraInstance.' - EXTRA!');
226                 } // END - if
227
228                 // Is the value instance valid?
229                 if (is_null($this->valueInstance)) {
230                         // Get the requested instance
231                         $this->valueInstance = ObjectFactory::createObjectByConfiguredName($registryKey . '_class', array($this->extraInstance));
232                 } // END - if
233         }
234
235         /**
236          * Opens a helper group with given group id and content or throws an
237          * exception if that group is already found regardless if it is open or
238          * closed.
239          *
240          * @param       $groupId        Group id to open
241          * @param       $content        Initial content to add to the group
242          * @param       $tag            HTML tag used to open this group
243          * @return      void
244          * @throws      HelperGroupAlreadyCreatedException      If the group was already created before
245          */
246         protected function openGroupByIdContent ($groupId, $content, $tag) {
247                 //* DEBUG: */ echo "OPEN:groupId={$groupId},content=<pre>".htmlentities($content)."</pre>\n";
248                 // Is the group already there?
249                 if (isset($this->groups[$groupId])) {
250                         // Then throw an exception here
251                         throw new HelperGroupAlreadyCreatedException(array($this, $groupId), self::EXCEPTION_GROUP_ALREADY_FOUND);
252                 } // END - if
253
254                 // Count one up
255                 $this->totalCounter++;
256
257                 // Add the group to the stack
258                 $this->groups[$this->totalCounter] = $groupId;
259                 $this->groups[$groupId]['opened']  = TRUE;
260                 $this->groups[$groupId]['content'] = sprintf(
261                         '<!-- group %s opened (length: %s, tag: %s) //-->%s' . PHP_EOL,
262                         $groupId,
263                         strlen($content),
264                         $tag,
265                         $content
266                 );
267                 $this->groups[$groupId]['tag'] = $tag;
268
269                 // Mark this group as previously opened
270                 $this->setPreviousGroupId($groupId);
271         }
272
273         /**
274          * Closes the previously opened group by added given content to it or
275          * throws an exception if no previous group was opened
276          *
277          * @param       $content        Content for previously opened group, or empty to use tag of opener
278          * @return      void
279          * @throws      HelperNoPreviousOpenedGroupException    If no previously opened group was found
280          */
281         public function closePreviousGroupByContent ($content = '') {
282                 // Check if any sub group was opened before
283                 if ($this->ifSubGroupOpenedPreviously()) {
284                         // Close it automatically
285                         $this->closePreviousSubGroupByContent();
286                 } // END - if
287
288                 // Check if any group was opened before
289                 if ($this->ifGroupOpenedPreviously() === FALSE) {
290                         // Then throw an exception
291                         throw new HelperNoPreviousOpenedGroupException(array($this, $content), self::EXCEPTION_NO_PREVIOUS_SUB_GROUP_OPENED);
292                 } // END - if
293
294                 // Get previous group
295                 $groupId = $this->getPreviousGroupId();
296
297                 // Is the content empty?
298                 if ((empty($content)) && (!empty($this->groups[$groupId]['tag']))) {
299                         // Get it from opener
300                         $content = sprintf(
301                                 "<!-- group %s auto-closed //--></%s>",
302                                 $groupId,
303                                 $this->groups[$groupId]['tag']
304                         );
305                 } // END - if
306
307                 // Add content to it and mark it as closed
308                 $this->groups[$groupId]['content'] .= sprintf(
309                         "<!-- group %s closed (length: %s, tag: %s) //-->%s\n",
310                         $groupId,
311                         strlen($content),
312                         $this->groups[$groupId]['tag'],
313                         $content
314                 );
315                 $this->groups[$groupId]['opened'] = FALSE;
316
317                 // Mark previous group as closed
318                 $this->setPreviousGroupId('');
319                 //* DEBUG: */ echo "CLOSE:groupId={$groupId}<br />\n";
320         }
321
322         /**
323          * Opens a helper sub group with given group id and content or throws an
324          * exception if that sub group is already found regardless if it is open or
325          * closed.
326          *
327          * @param       $subGroupId             Sub group id to open
328          * @param       $content                Initial content to add to the sub group
329          * @param       $tag                    HTML tag used to open this group
330          * @return      void
331          * @throws      HelperSubGroupAlreadyCreatedException   If the sub group was already created before
332          */
333         protected function openSubGroupByIdContent ($subGroupId, $content, $tag) {
334                 //* DEBUG: */ echo "OPEN:subGroupId={$subGroupId},content=".htmlentities($content)."<br />\n";
335                 // Is the group already there?
336                 if (isset($this->subGroups[$subGroupId])) {
337                         // Then throw an exception here
338                         throw new HelperSubGroupAlreadyCreatedException(array($this, $subGroupId), self::EXCEPTION_SUB_GROUP_ALREADY_FOUND);
339                 } // END - if
340
341                 // Count one up
342                 $this->totalCounter++;
343
344                 // Add the group to the stack
345                 $this->subGroups[$this->totalCounter] = $subGroupId;
346                 $this->subGroups[$subGroupId]['opened']  = TRUE;
347                 $this->subGroups[$subGroupId]['content'] = sprintf("<!-- sub-group %s opened (length: %s, tag: %s) //-->%s\n", $subGroupId, strlen($content), $tag, $content);
348                 $this->subGroups[$subGroupId]['tag'] = $tag;
349
350                 // Mark this group as previously opened
351                 $this->setPreviousSubGroupId($subGroupId);
352         }
353
354         /**
355          * Closes the previously opened sub group by added given content to it or
356          * throws an exception if no previous sub group was opened
357          *
358          * @param       $content        Content for previously opened sub group, or leave empty to use div/span of openener
359          * @return      void
360          * @throws      HelperNoPreviousOpenedSubGroupException If no previously opened sub group was found
361          */
362         public function closePreviousSubGroupByContent ($content = '') {
363                 // Check if any sub group was opened before
364                 if ($this->ifSubGroupOpenedPreviously() === FALSE) {
365                         // Then throw an exception
366                         throw new HelperNoPreviousOpenedSubGroupException(array($this, $content), self::EXCEPTION_NO_PREVIOUS_SUB_GROUP_OPENED);
367                 } // END - if
368
369                 // Get previous sub group
370                 $subGroupId = $this->getPreviousSubGroupId();
371
372                 // Is the content empty?
373                 if ((empty($content)) && (!empty($this->subGroups[$subGroupId]['tag']))) {
374                         // Get it from opener
375                         $content = sprintf('<!-- sub-group %s auto-closed //--></%s>', $subGroupId, $this->subGroups[$subGroupId]['tag']);
376                 } // END - if
377
378                 // Add content to it and mark it as closed
379                 $this->subGroups[$subGroupId]['content'] .= sprintf('<!-- sub-group %s closed (length: %s, tag: %s) //-->%s' . PHP_EOL, $subGroupId, strlen($content), $this->subGroups[$subGroupId]['tag'], $content);
380                 $this->subGroups[$subGroupId]['opened'] = FALSE
381                 ;
382
383                 // Mark previous sub group as closed
384                 $this->setPreviousSubGroupId('');
385                 //* DEBUG: */ echo "CLOSE:subGroupId={$subGroupId}<br />\n";
386         }
387
388         /**
389          * Renders all group and sub group in their order
390          *
391          * @return      $content        Rendered HTML content
392          */
393         public function renderContent () {
394                 // Initialize content
395                 $content = '';
396
397                 // Is header content there?
398                 if (isset($this->groups['header'])) {
399                         // Then add it
400                         $content .= $this->groups['header']['content'] . PHP_EOL;
401                 } // END - if
402
403                 // Initiate content
404                 $content .= $this->getContent();
405
406                 // Now "walk" through all groups and sub-groups
407                 for ($idx = 1; $idx <= $this->totalCounter; $idx++) {
408                         // Is this a sub/group and is it closed?
409                         if ((isset($this->groups[$idx])) && ($this->groups[$this->groups[$idx]]['opened'] === FALSE)) {
410                                 // Then add it's content
411                                 $groupContent = trim($this->groups[$this->groups[$idx]]['content']);
412                                 //* DEBUG: */ echo "group={$this->groups[$idx]},content=<pre>".htmlentities($groupContent)."</pre><br />\n";
413                                 $content .= $groupContent;
414                         } elseif ((isset($this->subGroups[$idx])) && ($this->subGroups[$this->subGroups[$idx]]['opened'] === FALSE)) {
415                                 // Then add it's content
416                                 $subGroupContent = $this->subGroups[$this->subGroups[$idx]]['content'];
417                                 //* DEBUG: */ echo "subgroup={$this->subGroups[$idx]},content=<pre>".htmlentities($subGroupContent)."</pre><br />\n";
418                                 $content .= trim($subGroupContent);
419                         } else {
420                                 // Something went wrong
421                                 $this->debugInstance(__METHOD__ . '(): Something unexpected happened here.');
422                         }
423                 } // END - for
424
425                 // Is footer content there?
426                 if (isset($this->groups['footer'])) {
427                         // Then add it
428                         $content .= $this->groups['footer']['content'] . PHP_EOL;
429                 } // END - if
430
431                 // Return it
432                 //* DEBUG: */ echo "content=<pre>".htmlentities($content)."</pre> (".strlen($content).")<br />\n";
433                 return $content;
434         }
435
436         /**
437          * Checks whether the specified group is opened
438          *
439          * @param       $groupId        Id of group to check
440          * @return      $isOpened       Whether the specified group is open
441          */
442         protected function ifGroupIsOpened ($groupId) {
443                 // Is the group open?
444                 $isOpened = ((isset($this->groups[$groupId])) && ($this->groups[$groupId]['opened'] === TRUE));
445
446                 // Return status
447                 return $isOpened;
448         }
449
450         /**
451          * Getter for direct field values
452          *
453          * @param       $fieldName              Name of the field we shall fetch
454          * @return      $fieldValue             Value from field
455          * @throws      NullPointerException    Thrown if $valueInstance is null
456          */
457         public function getValueField ($fieldName) {
458                 // Init value
459                 $fieldValue = NULL;
460
461                 // The $valueInstance attribute should not be null!
462                 if (is_null($this->getValueInstance())) {
463                         // Throws an exception here
464                         throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
465                 } // END - if
466
467                 // Is the field set?
468                 if ($this->getValueInstance()->isFieldSet($fieldName)) {
469                         // Get the field value
470                         $fieldValue = $this->getValueInstance()->getField($fieldName);
471                         //* DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput($fieldName.'[]='.gettype($fieldValue).'('.strlen($fieldValue).') - Value instance!');
472                 } elseif ((!is_null($this->extraInstance)) && ($this->extraInstance->isFieldSet($fieldName))) {
473                         // So try the extra instance
474                         $fieldValue = $this->extraInstance->getField($fieldName);
475                         //* DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput($fieldName.'[]='.gettype($fieldValue).'('.strlen($fieldValue).') - Extra instance!');
476                 } else {
477                         // Field is not set
478                         if ((!is_null($this->extraInstance)) && ($fieldName == 'city_name')) die('<pre>'.print_r($this->extraInstance, TRUE).'</pre>');
479                         $this->debugOutput('[' . __METHOD__ . ':' . __LINE__ . '] fieldName=' . $fieldName . ' is not set! - @TODO');
480                 } // END - if
481
482                 // Return it
483                 return $fieldValue;
484         }
485
486         /**
487          * Getter for value instance
488          *
489          * @return      $valueInstance  Instance of the class holding our values
490          */
491         public final function getValueInstance () {
492                 return $this->valueInstance;
493         }
494
495         /**
496          * Check whether a group was opened previously
497          *
498          * @return      $groupOpened    Whether any group was opened before
499          */
500         protected final function ifGroupOpenedPreviously () {
501                 $groupOpened = (!empty($this->previousGroupId));
502                 return $groupOpened;
503         }
504
505         /**
506          * Check whether a group was opened previously
507          *
508          * @return      $subGroupOpened         Whether any group was opened before
509          */
510         protected final function ifSubGroupOpenedPreviously () {
511                 $subGroupOpened = (!empty($this->previousSubGroupId));
512                 return $subGroupOpened;
513         }
514
515         /**
516          * Getter for previous group id
517          *
518          * @return      $previousGroupId        Id of previously opened group
519          */
520         protected final function getPreviousGroupId () {
521                 return $this->previousGroupId;
522         }
523
524         /**
525          * Setter for previous group id
526          *
527          * @param       $previousGroupId        Id of previously opened group
528          * @return      void
529          */
530         protected final function setPreviousGroupId ($previousGroupId) {
531                 $this->previousGroupId = (string) $previousGroupId;
532         }
533
534         /**
535          * Getter for previous sub group id
536          *
537          * @return      $previousSubGroupId             Id of previously opened sub group
538          */
539         protected final function getPreviousSubGroupId () {
540                 return $this->previousSubGroupId;
541         }
542
543         /**
544          * Setter for previous sub group id
545          *
546          * @param       $previousSubGroupId             Id of previously opened sub group
547          * @return      void
548          */
549         protected final function setPreviousSubGroupId ($previousSubGroupId) {
550                 $this->previousSubGroupId = (string) $previousSubGroupId;
551         }
552 }
553
554 // [EOF]
555 ?>