5debdda12b3dc07c83cd3350cd837b71126e1bb4
[shipsimu.git] / inc / classes / main / helper / web / class_WebFormHelper.php
1 <?php
2 /**
3  * A helper for constructing web forms
4  *
5  * @author              Roland Haeder <webmaster@ship-simu.org>
6  * @version             0.0.0
7  * @copyright   Copyright(c) 2007, 2008 Roland Haeder, this is free software
8  * @license             GNU GPL 3.0 or any newer version
9  * @link                http://www.ship-simu.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 WebFormHelper extends BaseHelper {
25         /**
26          * Instance to the class which provides field values
27          */
28         private $valueInstance = null;
29
30         /**
31          * Wether the form tag is opened (keep at false or else your forms will
32          * never work!)
33          */
34         private $formOpened = false;
35
36         /**
37          * Name of the form
38          */
39         private $formName = "";
40
41         /**
42          * Wether the group is opened or not
43          */
44         private $groupOpened = false;
45
46         /**
47          * Wether the sub group is opened or not
48          */
49         private $subGroupOpened = false;
50
51         /**
52          * Name of the sub group
53          */
54         private $subGroupName = "";
55
56         // Class Constants
57         const EXCEPTION_FORM_NAME_INVALID       = 0x030;
58         const EXCEPTION_CLOSED_FORM             = 0x031;
59         const EXCEPTION_OPENED_FORM             = 0x032;
60         const EXCEPTION_UNEXPECTED_CLOSED_GROUP = 0x033;
61
62         /**
63          * Protected constructor
64          *
65          * @return      void
66          */
67         protected function __construct () {
68                 // Call parent constructor
69                 parent::__construct(__CLASS__);
70
71                 // Set part description
72                 $this->setObjectDescription("Helper class for HTML forms");
73
74                 // Create unique ID number
75                 $this->generateUniqueId();
76         }
77
78         /**
79          * Creates the helper class with the given template engine instance and form name
80          *
81          * @param       $templateInstance       An instance of a valid template engine
82          * @param       $formName                       Name of the form
83          * @param       $formId                         Value for "id" attribute (default: $formName)
84          * @return      $helperInstance         A preparedf instance of this class
85          */
86         public final static function createWebFormHelper (CompileableTemplate $templateInstance, $formName, $formId = false) {
87                 // Get new instance
88                 $helperInstance = new WebFormHelper();
89
90                 // Set template instance
91                 $helperInstance->setTemplateInstance($templateInstance);
92
93                 // Is the form id not set?
94                 if ($formId === false) {
95                         // Use form id from form name
96                         $formId = $formName;
97                 }
98
99                 // Create the form
100                 $helperInstance->addFormTag($formName, $formId);
101
102                 // Return the prepared instance
103                 return $helperInstance;
104         }
105
106         /**
107          * Pre-fetches field default values from the given registry key instance into this class
108          *
109          * @param       $registryKey
110          * @return      void
111          * @throws      NullPointerException    If an instance from registry is null
112          */
113         public function prefetchFieldValues ($registryKey) {
114                 // Get the required instance
115                 $this->valueInstance = Registry::getRegistry()->getInstance($registryKey);
116
117                 // Is the instance valid?
118                 if (is_null($this->valueInstance)) {
119                         // Throw an exception
120                         throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
121                 } // END - if
122         }
123
124         /**
125          * Add the form tag or close it an already opened form tag
126          *
127          * @param       $formName       Name of the form (default: false)
128          * @param       $formId         Id of the form (attribute "id"; default: false)
129          * @return      void
130          * @throws      InvalidFormNameException        If the form name is invalid (=false)
131          */
132         public function addFormTag ($formName = false, $formId = false) {
133                 // When the form is not yet opened at least form name must be valid
134                 if (($this->formOpened === false) && ($formName === false)) {
135                         // Thrown an exception
136                         throw new InvalidFormNameException ($this, self::EXCEPTION_FORM_NAME_INVALID);
137                 }
138
139                 // Close the form is default
140                 $formContent = "</form>";
141
142                 // Check wether we shall open or close the form
143                 if ($this->formOpened === false) {
144                         // Add HTML code
145                         $formContent = sprintf("<form name=\"%s\" class=\"forms\" action=\"%s/%s\" method=\"%s\" target=\"%s\"",
146                                 $formName,
147                                 $this->getConfigInstance()->readConfig('base_url'),
148                                 $this->getConfigInstance()->readConfig('form_action'),
149                                 $this->getConfigInstance()->readConfig('form_method'),
150                                 $this->getConfigInstance()->readConfig('form_target')
151                         );
152
153                         // Is the form id set?
154                         if ($formId !== false) {
155                                 // Then add it as well
156                                 $formContent .= sprintf(" id=\"%s_form\"",
157                                         $formId
158                                 );
159                         }
160
161                         // Add close bracket
162                         $formContent .= ">";
163
164                         // Open the form and remeber the form name
165                         $this->formOpened = true;
166                         $this->formName = $formName;
167                 } else {
168                         // Add the hidden field required to identify safely this form
169                         $this->addInputHiddenField('form', $this->formName);
170
171                         // Is a group open?
172                         if ($this->groupOpened === true) {
173                                 // Then automatically close it here
174                                 $this->addFormGroup("", "");
175                         }
176
177                         /* @TODO Add some unique PIN here to bypass problems with some browser and/or extensions */
178                         // Simply close it
179                         $this->formOpened = false;
180                 }
181
182                 // Add it to the content
183                 $this->addContent($formContent);
184         }
185
186         /**
187          * Add a text input tag to the form or throw an exception if it is not yet
188          * opened. The field's name will be set as id.
189          *
190          * @param       $fieldName              Input field name
191          * @param       $fieldValue             Input default value (default: empty)
192          * @return      void
193          * @throws      FormClosedException             If the form is not yet opened
194          */
195         public function addInputTextField ($fieldName, $fieldValue = "") {
196                 // Is the form opened?
197                 if ($this->formOpened === false) {
198                         // Throw an exception
199                         throw new FormClosedException (array($this, $fieldName), self::EXCEPTION_CLOSED_FORM);
200                 }
201
202                 // Generate the content
203                 $inputContent = sprintf("<input type=\"text\" class=\"textfield\" id=\"%s\" name=\"%s\" value=\"%s\" />",
204                         $fieldName,
205                         $fieldName,
206                         $fieldValue
207                 );
208
209                 // And add it maybe with a "li" tag
210                 $this->addContent($inputContent);
211         }
212
213         /**
214          * Add a text input tag to the form with pre-loaded default value
215          *
216          * @param       $fieldName      Input field name
217          * @return      void
218          */
219         public function addInputTextFieldWithDefault ($fieldName) {
220                 // Get the value from instance
221                 $fieldValue = call_user_func_array(array($this->valueInstance, "getField"), array($fieldName));
222                 //* DEBUG: */ echo __METHOD__.":".$fieldName."=".$fieldValue."<br />\n";
223
224                 // Add the text field
225                 $this->addInputTextField($fieldName, $fieldValue);
226         }
227
228         /**
229          * Add a password input tag to the form or throw an exception if it is not
230          * yet opened. The field's name will be set as id.
231          *
232          * @param       $fieldName                      Input field name
233          * @param       $fieldValue                     Input default value (default: empty)
234          * @return      void
235          * @throws      FormClosedException             If the form is not yet opened
236          */
237         public function addInputPasswordField ($fieldName, $fieldValue = "") {
238                 // Is the form opened?
239                 if ($this->formOpened === false) {
240                         // Throw an exception
241                         throw new FormClosedException (array($this, $fieldName), self::EXCEPTION_CLOSED_FORM);
242                 }
243
244                 // Generate the content
245                 $inputContent = sprintf("<input type=\"password\" class=\"password\" id=\"%s\" name=\"%s\" value=\"%s\" />",
246                         $fieldName,
247                         $fieldName,
248                         $fieldValue
249                 );
250
251                 // And add it
252                 $this->addContent($inputContent);
253         }
254
255         /**
256          * Add a hidden input tag to the form or throw an exception if it is not
257          * yet opened. The field's name will be set as id.
258          *
259          * @param       $fieldName                      Input field name
260          * @param       $fieldValue                     Input default value (default: empty)
261          * @return      void
262          * @throws      FormClosedException             If the form is not yet opened
263          */
264         public function addInputHiddenField ($fieldName, $fieldValue = "") {
265                 // Is the form opened?
266                 if ($this->formOpened === false) {
267                         // Throw an exception
268                         throw new FormClosedException (array($this, $fieldName), self::EXCEPTION_CLOSED_FORM);
269                 }
270
271                 // Generate the content
272                 $inputContent = sprintf("<input type=\"hidden\" name=\"%s\" value=\"%s\" />",
273                         $fieldName,
274                         $fieldValue
275                 );
276
277                 // And add it
278                 $this->addContent($inputContent);
279         }
280
281         /**
282          * Add a checkbox input tag to the form or throw an exception if it is not
283          * yet opened. The field's name will be set as id.
284          *
285          * @param       $fieldName                      Input field name
286          * @param       $fieldChecked           Wether the field is checked (defaut: checked)
287          * @return      void
288          * @throws      FormClosedException             If the form is not yet opened
289          */
290         public function addInputCheckboxField ($fieldName, $fieldChecked = true) {
291                 // Is the form opened?
292                 if ($this->formOpened === false) {
293                         // Throw an exception
294                         throw new FormClosedException (array($this, $fieldName), self::EXCEPTION_CLOSED_FORM);
295                 }
296
297                 // Set wether the check box is checked...
298                 $checked = " checked=\"checked\"";
299                 if ($fieldChecked === false) $checked = " ";
300
301                 // Generate the content
302                 $inputContent = sprintf("<input type=\"checkbox\" name=\"%s\" class=\"checkbox\" id=\"%s\" value=\"1\"%s/>",
303                         $fieldName,
304                         $fieldName,
305                         $checked
306                 );
307
308                 // And add it
309                 $this->addContent($inputContent);
310         }
311
312         /**
313          * Add a reset input tag to the form or throw an exception if it is not
314          * yet opened. The field's name will be set as id.
315          *
316          * @param       $buttonText             Text displayed on the button
317          * @return      void
318          * @throws      FormClosedException             If the form is not yet opened
319          */
320         public function addInputResetButton ($buttonText) {
321                 // Is the form opened?
322                 if ($this->formOpened === false) {
323                         // Throw an exception
324                         throw new FormClosedException (array($this, "reset"), self::EXCEPTION_CLOSED_FORM);
325                 }
326
327                 // Generate the content
328                 $inputContent = sprintf("<input type=\"reset\" class=\"reset_button\" id=\"%s_reset\" value=\"%s\" />",
329                         $this->formName,
330                         $buttonText
331                 );
332
333                 // And add it
334                 $this->addContent($inputContent);
335         }
336
337         /**
338          * Add a reset input tag to the form or throw an exception if it is not
339          * yet opened. The field's name will be set as id.
340          *
341          * @param       $buttonText                     Text displayed on the button
342          * @return      void
343          * @throws      FormClosedException             If the form is not yet opened
344          */
345         public function addInputSubmitButton ($buttonText) {
346                 // Is the form opened?
347                 if ($this->formOpened === false) {
348                         // Throw an exception
349                         throw new FormClosedException (array($this, "submit"), self::EXCEPTION_CLOSED_FORM);
350                 }
351
352                 // Generate the content
353                 $inputContent = sprintf("<input type=\"submit\" class=\"submit_button\" id=\"%s_submit\" name=\"%s_button\" value=\"%s\" />",
354                         $this->formName,
355                         $this->formName,
356                         $buttonText
357                 );
358
359                 // And add it
360                 $this->addContent($inputContent);
361         }
362
363         /**
364          * Add a form group or close an already opened and open a new one
365          *
366          * @param       $groupName      Name of the group
367          * @param       $groupText      Text including HTML to show above this group
368          * @return      void
369          * @throws      FormClosedException             If no form has been opened before
370          * @throws      EmptyVariableException  If $groupName is not set
371          */
372         public function addFormGroup ($groupName, $groupText) {
373                 // Is a form opened?
374                 if ($this->formOpened === false) {
375                         // Throw exception here
376                         throw new FormClosedException(array($this, $groupName), self::EXCEPTION_CLOSED_FORM);
377                 }
378
379                 // At least the group name should be set
380                 if ((empty($groupName)) && ($this->groupOpened === false)) {
381                         // Throw exception here
382                         throw new EmptyVariableException(array($this, 'groupName'), self::EXCEPTION_UNEXPECTED_EMPTY_STRING);
383                 }
384
385                 // Initialize content with closing div by default
386                 $content = "    </div>\n</div><!-- Group - CLOSE //-->";
387
388                 // Is this group opened?
389                 if ($this->groupOpened === false) {
390                         // Begin the div/span blocks
391                         $content = sprintf("<!-- Group %s - OPEN //-->
392 <div class=\"group_box\" id=\"%s_group_box\">
393         <span class=\"group_text\" id=\"%s_group_text\">
394                 %s
395         </span>
396         <div class=\"group_field\" id=\"%s_group_field\">",
397                                 $groupName,
398                                 $groupName,
399                                 $groupName,
400                                 $groupText,
401                                 $groupName
402                         );
403
404                         // Add the content
405                         $this->addContent($content);
406
407                         // Switch the state
408                         $this->groupOpened = true;
409                 } else {
410                         // Is a sub group opened?
411                         if ($this->subGroupOpened === true) {
412                                 // Close it here
413                                 $this->addFormSubGroup("", "");
414                         }
415
416                         // Add the content
417                         $this->addContent($content);
418
419                         // Switch the state
420                         $this->groupOpened = false;
421
422                         // All call it again if the group name is not empty
423                         if (!empty($groupName)) {
424                                 $this->addFormGroup($groupName, $groupText);
425                         }
426                 }
427         }
428
429         /**
430          * Add a form sub group or close an already opened and open a new one or
431          * throws an exception if no group has been opened before or if the sub
432          * group name is empty.
433          *
434          * @param       $subGroupName   Name of the group
435          * @param       $subGroupText   Text including HTML to show above this group
436          * @return      void
437          * @throws      FormGroupClosedException        If no group has been opened before
438          * @throws      EmptyVariableException          If $subGroupName is not set
439          */
440         public function addFormSubGroup ($subGroupName, $subGroupText) {
441                 // Is a group opened?
442                 if ($this->groupOpened === false) {
443                         // Throw exception here
444                         throw new FormGroupClosedException(array($this, $subGroupName), self::EXCEPTION_UNEXPECTED_CLOSED_GROUP);
445                 }
446
447                 // At least the sub group name should be set
448                 if ((empty($subGroupName)) && ($this->subGroupOpened === false)) {
449                         // Throw exception here
450                         throw new EmptyVariableException(array($this, 'groupName'), self::EXCEPTION_UNEXPECTED_EMPTY_STRING);
451                 }
452
453                 // Initialize content with closing div by default
454                 $content = "    </div>\n</div><!-- Sub group- CLOSE //-->";
455
456                 // Is this group opened?
457                 if ($this->subGroupOpened === false) {
458                         // Begin the span block
459                         $content = sprintf("<!-- Sub group %s - OPEN //-->
460 <div class=\"subgroup_box\" id=\"%s_subgroup_box\">
461         <span class=\"subgroup_text\" id=\"%s_subgroup_text\">
462                 %s
463         </span>
464         <div class=\"subgroup_field\" id=\"%s_subgroup_field\">",
465                                 $subGroupName,
466                                 $subGroupName,
467                                 $subGroupName,
468                                 $subGroupText,
469                                 $subGroupName
470                         );
471
472                         // Add the content
473                         $this->addContent($content);
474
475                         // Switch the state and remeber the name
476                         $this->subGroupOpened = true;
477                         $this->subGroupName = $subGroupName;
478                 } else {
479                         // Add the content
480                         $this->addContent($content);
481
482                         // Switch the state
483                         $this->subGroupOpened = false;
484
485                         // All call it again if sub group name is not empty
486                         if (!empty($subGroupName)) {
487                                 $this->addFormSubGroup($subGroupName, $subGroupText);
488                         }
489                 }
490         }
491
492         /**
493          * Add text surrounded by a span block when there is a group opened before
494          * or else by a div block.
495          *
496          * @param       $fieldName                      Field name
497          * @param       $fieldText                      Text for the field
498          * @return      void
499          * @throws      FormClosedException             If the form is not yet opened
500          */
501         public function addFieldText ($fieldName, $fieldText) {
502                 // Is the form opened?
503                 if ($this->formOpened === false) {
504                         // Throw an exception
505                         throw new FormClosedException (array($this, $fieldName), self::EXCEPTION_CLOSED_FORM);
506                 }
507
508                 // Set the block type
509                 $block = "div";
510                 if ($this->groupOpened === true) $block = "span";
511
512                 // Generate the content
513                 $inputContent = sprintf("       <%s id=\"%s_text\">
514                 %s
515         </%s>",
516                         $block,
517                         $fieldName,
518                         $fieldText,
519                         $block
520                 );
521
522                 // And add it
523                 $this->addContent($inputContent);
524         }
525
526         /**
527          * Add text (notes) surrounded by a div block.┬áStill opened groups or sub
528          * groups will be automatically closed.
529          *
530          * @param       $formNotes      The form notes we shell addd
531          * @return      void
532          * @throws      FormClosedException             If the form is not yet opened
533          */
534         public function addFormNote ($formNotes) {
535                 // Is the form opened?
536                 if ($this->formOpened === false) {
537                         // Throw an exception
538                         throw new FormClosedException (array($this, "form_notes"), self::EXCEPTION_CLOSED_FORM);
539                 }
540
541                 // Is a group open?
542                 if ($this->groupOpened === true) {
543                         // Then automatically close it here
544                         $this->addFormGroup("", "");
545                 }
546
547                 // Generate the content
548                 $inputContent = sprintf("       <div id=\"form_note\">
549                 %s
550         </div>",
551                         $formNotes
552                 );
553
554                 // And add it
555                 $this->addContent($inputContent);
556         }
557
558         /**
559          * Checks wether the registration requires a valid email address
560          *
561          * @return      $required       Wether the email address is required
562          */
563         public function ifRegisterRequiresEmailVerification () {
564                 $required = ($this->getConfigInstance()->readConfig('register_requires_email') == "Y");
565                 return $required;
566         }
567
568         /**
569          * Checks wether profile data shall be asked
570          *
571          * @return      $required       Wether profile shall be asked
572          */
573         public function ifRegisterIncludesProfile () {
574                 $required = ($this->getConfigInstance()->readConfig('register_includes_profile') == "Y");
575                 return $required;
576         }
577
578         /**
579          * Checks wether personal data shall be asked
580          *
581          * @return      $required       Wether personal data shall be asked
582          */
583         public function ifRegisterIncludesPersonaData () {
584                 $required = ($this->getConfigInstance()->readConfig('register_personal_data') == "Y");
585                 return $required;
586         }
587
588         /**
589          * Checks wether email addresses can only be once used
590          *
591          * @return      $isUnique
592          */
593         public function ifEmailMustBeUnique () {
594                 $isUnique = ($this->getConfigInstance()->readConfig('register_email_unique') == "Y");
595                 return $isUnique;
596         }
597
598         /**
599          * Checks wether the specified chat protocol is enabled in this form
600          *
601          * @return      $required       Wether the specified chat protocol is enabled
602          */
603         public function ifChatEnabled ($chatProtocol) {
604                 $required = ($this->getConfigInstance()->readConfig(sprintf("chat_enabled_%s", $chatProtocol)) == "Y");
605                 return $required;
606         }
607
608         /**
609          * Checks wether login is enabled or disabled
610          *
611          * @return      $isEnabled      Wether the login is enabled or disabled
612          */
613         public function ifLoginIsEnabled () {
614                 $isEnabled = ($this->getConfigInstance()->readConfig('login_enabled') == "Y");
615                 return $isEnabled;
616         }
617
618         /**
619          * Checks wether login shall be done by username
620          *
621          * @return      $isEnabled      Wether the login shall be done by username
622          */
623         public function ifLoginWithUsername () {
624                 $isEnabled = ($this->getConfigInstance()->readConfig('login_type') == "username");
625                 return $isEnabled;
626         }
627
628         /**
629          * Checks wether login shall be done by email
630          *
631          * @return      $isEnabled      Wether the login shall be done by email
632          */
633         public function ifLoginWithEmail () {
634                 $isEnabled = ($this->getConfigInstance()->readConfig('login_type') == "email");
635                 return $isEnabled;
636         }
637
638         /**
639          * Checks wether guest login is allowed
640          *
641          * @return      $isAllowed      Wether guest login is allowed
642          */
643         public function ifGuestLoginAllowed () {
644                 $isAllowed = ($this->getConfigInstance()->readConfig('guest_login_allowed') == "Y");
645                 return $isAllowed;
646         }
647
648         /**
649          * Checks wether the email address change must be confirmed
650          *
651          * @return      $requireConfirm         Wether email change must be confirmed
652          */
653         public function ifEmailChangeRequireConfirmation () {
654                 $requireConfirm = ($this->getConfigInstance()->readConfig('email_change_confirmation') == "Y");
655                 return $requireConfirm;
656         }
657
658         /**
659          * Checks wether the rules has been updated
660          *
661          * @return      $rulesUpdated   Wether rules has been updated
662          */
663         public function ifRulesHaveChanged () {
664                 /* @TODO Implement check if rules have been changed */
665                 return false;
666         }
667
668         /**
669          * Checks wether email change is allowed
670          *
671          * @return      $emailChange    Wether changing email address is allowed
672          */
673         public function ifEmailChangeAllowed () {
674                 $emailChange = ($this->getConfigInstance()->readConfig('email_change_allowed') == "Y");
675                 return $emailChange;
676         }
677
678         /**
679          * Flushs the content out (not yet secured against open forms, etc.!) or
680          * throw an exception if it is not yet closed
681          *
682          * @return      void
683          * @throws      FormOpenedException             If the form is still open
684          */
685         public function flushContent () {
686                 // Is the form still open?
687                 if ($this->formOpened === true) {
688                         // Throw an exception
689                         throw new FormOpenedException ($this, self::EXCEPTION_OPENED_FORM);
690                 }
691
692                 // Send content to template engine
693                 $this->getTemplateInstance()->assignVariable($this->formName, $this->getContent());
694         }
695
696         /**
697          * Getter for direct field values
698          *
699          * @param       $fieldName              Name of the field we shall fetch
700          * @return      $fieldValue             Value from field
701          */
702         public function getField ($fieldName) {
703                 // Get the field value
704                 $fieldValue = call_user_func_array(array($this->valueInstance, "getField"), array($fieldName));
705
706                 // Return it
707                 return $fieldValue;
708         }
709 }
710
711 // [EOF]
712 ?>