Overview

Packages

  • Core
    • Authentication
    • Backend
    • Cache
    • CEC
    • Chain
    • ContentType
    • Database
    • Datatype
    • Debug
    • Exception
    • Frontend
      • Search
      • URI
      • Util
    • GenericDB
      • Model
    • GUI
      • HTML
    • I18N
    • LayoutHandler
    • Log
    • Security
    • Session
    • Util
    • Validation
    • Versioning
    • XML
  • Module
    • ContentSitemapHtml
    • ContentSitemapXml
    • ContentUserForum
    • NavigationTop
  • mpAutoloaderClassMap
  • None
  • Plugin
    • ContentAllocation
    • CronjobOverview
    • FormAssistant
    • FrontendLogic
    • FrontendUsers
    • Linkchecker
    • ModRewrite
    • Newsletter
    • Repository
      • FrontendNavigation
      • KeywordDensity
    • SearchSolr
    • SmartyWrapper
    • UrlShortener
    • UserForum
    • Workflow
  • PluginManager
  • Setup
    • Form
    • GUI
    • Helper
      • Environment
      • Filesystem
      • MySQL
      • PHP
    • UpgradeJob

Classes

  • cContentTypePifaForm
  • DefaultFormModule
  • DefaultFormProcessor
  • ExampleOptionsDatasource
  • MailedFormProcessor
  • Pifa
  • PifaAbstractFormModule
  • PifaAbstractFormProcessor
  • PifaAjaxHandler
  • PifaExternalOptionsDatasourceInterface
  • PifaField
  • PifaFieldCollection
  • PifaForm
  • PifaFormCollection
  • PifaLeftBottomPage
  • PifaRightBottomFormDataPage
  • PifaRightBottomFormFieldsPage
  • PifaRightBottomFormPage
  • SolrRightBottomPage

Exceptions

  • PifaDatabaseException
  • PifaException
  • PifaIllegalStateException
  • PifaMailException
  • PifaNotImplementedException
  • PifaNotYetStoredException
  • PifaValidationException
  • Overview
  • Package
  • Class
  • Tree
  • Deprecated
  • Todo
   1: <?php
   2: 
   3: /**
   4:  *
   5:  * @package Plugin
   6:  * @subpackage FormAssistant
   7:  * @version SVN Revision $Rev:$
   8:  * @author marcus.gnass
   9:  * @copyright four for business AG
  10:  * @link http://www.4fb.de
  11:  */
  12: 
  13: // assert CONTENIDO framework
  14: defined('CON_FRAMEWORK') || die('Illegal call: Missing framework initialization - request aborted.');
  15: 
  16: /**
  17:  * PIFA field collection.
  18:  *
  19:  * @author marcus.gnass
  20:  */
  21: class PifaFieldCollection extends ItemCollection {
  22: 
  23:     /**
  24:      * Creates a PIFA field collection.
  25:      *
  26:      * @param mixed $where clause to be used to load items or false
  27:      */
  28:     public function __construct($where = false) {
  29:         parent::__construct(cRegistry::getDbTableName('pifa_field'), 'idfield');
  30:         $this->_setItemClass('PifaField');
  31:         if (false !== $where) {
  32:             $this->select($where);
  33:         }
  34:     }
  35: 
  36:     /**
  37:      * Reorders a forms fields according to the given.
  38:      *
  39:      * @param int $idform
  40:      * @param string $idfields containing a CSV list of idfield as integer
  41:      */
  42:     public static function reorder($idform, $idfields) {
  43:         $sql = "-- PifaFieldCollection::reorder()
  44:             UPDATE
  45:                 " . cRegistry::getDbTableName('pifa_field') . "
  46:             SET
  47:                 field_rank = FIND_IN_SET(idfield, '$idfields')
  48:             WHERE
  49:                 idform = $idform
  50:             ;";
  51: 
  52:         cRegistry::getDb()->query($sql);
  53:     }
  54: }
  55: 
  56: /**
  57:  * contains meta data of a PIFA field
  58:  *
  59:  * @author marcus.gnass
  60:  */
  61: class PifaField extends Item {
  62: 
  63:     /**
  64:      * Size to use for VARCHAR fields.
  65:      * Remember: the maximum row size for the used table type, not counting
  66:      * BLOBs, is 65535.
  67:      *
  68:      * @var int
  69:      * @todo PIFA should be able to calculate the size for one record by the
  70:      *       size of its fields and handle it accordingly.
  71:      */
  72:     const VARCHAR_SIZE = 255;
  73: 
  74:     /**
  75:      * Input field for single-line text.
  76:      *
  77:      * @var int
  78:      */
  79:     const INPUTTEXT = 1;
  80: 
  81:     /**
  82:      * Input field for multi-line text.
  83:      *
  84:      * @var int
  85:      */
  86:     const TEXTAREA = 2;
  87: 
  88:     /**
  89:      * Input field for single-line password.
  90:      *
  91:      * @var int
  92:      */
  93:     const INPUTPASSWORD = 3;
  94: 
  95:     /**
  96:      * Radiobox.
  97:      *
  98:      * @var int
  99:      */
 100:     const INPUTRADIO = 4;
 101: 
 102:     /**
 103:      * Checkbox
 104:      *
 105:      * @var int
 106:      */
 107:     const INPUTCHECKBOX = 5;
 108: 
 109:     /**
 110:      * Selectbox allowing for selection of a single option.
 111:      *
 112:      * @var int
 113:      */
 114:     const SELECT = 6;
 115: 
 116:     /**
 117:      * Selectbox allowing for selection of multiple options.
 118:      *
 119:      * @var int
 120:      */
 121:     const SELECTMULTI = 7;
 122: 
 123:     /**
 124:      * Input field for date selection.
 125:      *
 126:      * @var int
 127:      */
 128:     const DATEPICKER = 8;
 129: 
 130:     /**
 131:      * Input field for file selection.
 132:      *
 133:      * @var int
 134:      */
 135:     const INPUTFILE = 9;
 136: 
 137:     /**
 138:      * Processbar.
 139:      *
 140:      * @var int
 141:      */
 142:     const PROCESSBAR = 10;
 143: 
 144:     /**
 145:      * Slider.
 146:      *
 147:      * @var int
 148:      */
 149:     const SLIDER = 11;
 150: 
 151:     // /**
 152:     // * Captcha.
 153:     // *
 154:     // * @var int
 155:     // */
 156:     // const CAPTCHA = 12;
 157: 
 158:     /**
 159:      * Button to submit a form.
 160:      *
 161:      * @var int
 162:      */
 163:     const BUTTONSUBMIT = 13;
 164: 
 165:     /**
 166:      * Button to reset a form.
 167:      *
 168:      * @var int
 169:      */
 170:     const BUTTONRESET = 14;
 171: 
 172:     /**
 173:      * Button to navigate back.
 174:      *
 175:      * @var int
 176:      */
 177:     const BUTTONBACK = 15;
 178: 
 179:     /**
 180:      *
 181:      * @var int
 182:      */
 183:     const MATRIX = 16;
 184: 
 185:     /**
 186:      * A text to be displayed between form fields.
 187:      * It's no form field on its own but should be handled like one.
 188:      *
 189:      * @var int
 190:      */
 191:     const PARA = 17;
 192: 
 193:     /**
 194:      * A hidden input field.
 195:      *
 196:      * @var int
 197:      */
 198:     const INPUTHIDDEN = 18;
 199: 
 200:     /**
 201:      * Begin of a fieldset.
 202:      *
 203:      * @var int
 204:      */
 205:     const FIELDSET_BEGIN = 19;
 206: 
 207:     /**
 208:      * End of a fieldset.
 209:      *
 210:      * @var int
 211:      */
 212:     const FIELDSET_END = 20;
 213: 
 214:     /**
 215:      * The form fields value.
 216:      *
 217:      * @var mixed
 218:      */
 219:     private $_value = NULL;
 220: 
 221:     /**
 222:      * The file that was transmitted in case of INPUTFILE.
 223:      *
 224:      * @var array
 225:      */
 226:     private $_file = NULL;
 227: 
 228:     /**
 229:      *
 230:      * @param mixed $id ID of item to be loaded or false
 231:      */
 232:     public function __construct($id = false) {
 233:         parent::__construct(cRegistry::getDbTableName('pifa_field'), 'idfield');
 234:         $this->setFilters(array(), array());
 235:         if (false !== $id) {
 236:             $this->loadByPrimaryKey($id);
 237:         }
 238:     }
 239: 
 240:     /**
 241:      * Rule has to be stripslashed to allow regular expressions with
 242:      * backslashes.
 243:      *
 244:      * @see Item::getField()
 245:      */
 246:     function getField($field) {
 247:         $value = parent::getField($field);
 248:         if ('rule' === $field) {
 249:             $value = stripslashes($value);
 250:         }
 251:         return $value;
 252:     }
 253: 
 254:     /**
 255:      * Getter for protected prop.
 256:      */
 257:     public function getLastError() {
 258:         return $this->lasterror;
 259:     }
 260: 
 261:     /**
 262:      * Returns this fields stored value.
 263:      *
 264:      * @return mixed the $_value
 265:      */
 266:     public function getValue() {
 267:         return $this->_value;
 268:     }
 269: 
 270:     /**
 271:      *
 272:      * @param mixed $_value
 273:      */
 274:     public function setValue($value) {
 275:         $this->_value = $value;
 276:     }
 277: 
 278:     /**
 279:      * keys: name, tmp_name
 280:      *
 281:      * @return array the $_file
 282:      */
 283:     public function getFile() {
 284:         return $this->_file;
 285:     }
 286: 
 287:     /**
 288:      *
 289:      * @param array $_file
 290:      */
 291:     public function setFile(array $_file) {
 292:         $this->_file = $_file;
 293:     }
 294: 
 295:     /**
 296:      *
 297:      * @throws PifaValidationException if an error occured
 298:      */
 299:     public function validate() {
 300: 
 301:         // get value
 302:         $values = $this->getValue();
 303:         if (NULL === $values) {
 304:             $values = $this->get('default_value');
 305:         }
 306: 
 307:         // value could be an array (for form fields with suffix '[]')
 308:         // so make it an array anyway ...
 309:         if (!is_array($values)) {
 310:             $values = array(
 311:                 $values
 312:             );
 313:         }
 314: 
 315:         foreach ($values as $value) {
 316: 
 317:             // if (self::CAPTCHA == $this->get('field_type')) {
 318:             // // check for captcha
 319:             // $securimage = new Securimage(array(
 320:             // 'session_name' => cRegistry::getClientId() . 'frontend'
 321:             // ));
 322:             // $isValid = $securimage->check($value);
 323:             // } else
 324: 
 325:             if (1 === cSecurity::toInteger($this->get('obligatory')) && 0 === strlen($value)) {
 326:                 // check for obligatory & rule
 327:                 $isValid = false;
 328:             } else if (0 < strlen($this->get('rule')) && in_array(preg_match($this->get('rule'), $value), array(
 329:                 false,
 330:                 0
 331:             ))) {
 332:                 // check for rule
 333:                 $isValid = false;
 334:             } else {
 335:                 $isValid = true;
 336:             }
 337: 
 338:             // throw error
 339:             if (true !== $isValid) {
 340:                 $error_message = $this->get('error_message');
 341:                 if (NULL === $error_message) {
 342:                     // $error_message = 'invalid data';
 343:                     $error_message = '';
 344:                 }
 345:                 throw new PifaValidationException(array(
 346:                     $this->get('idfield') => $error_message
 347:                 ));
 348:             }
 349:         }
 350:     }
 351: 
 352:     /**
 353:      * Returns HTML for this form that should be displayed in frontend.
 354:      *
 355:      * @param array $errors to be displayed for form field
 356:      * @return string
 357:      */
 358:     public function toHtml(array $errors = NULL) {
 359:         $out = '';
 360:         switch (cSecurity::toInteger($this->get('field_type'))) {
 361: 
 362:             case self::FIELDSET_BEGIN:
 363: 
 364:                 // optional class for field
 365:                 if (0 < strlen(trim($this->get('css_class')))) {
 366:                     $class = ' class="' . implode(' ', explode(',', $this->get('css_class'))) . '"';
 367:                 }
 368:                 $out .= "\n\t<fieldset$class>";
 369:                 // add optional legend/description
 370:                 if (1 === cSecurity::toInteger($this->get('display_label'))) {
 371:                     $label = $this->get('label');
 372:                     $out .= "\n\t<legend>$label</legend>";
 373:                 }
 374: 
 375:                 return $out;
 376:                 break;
 377: 
 378:             case self::FIELDSET_END:
 379: 
 380:                 return "\n\t</fieldset>";
 381:                 break;
 382: 
 383:             default:
 384: 
 385:                 // build HTML content
 386:                 $content = array();
 387:                 try {
 388:                     $content[] = $this->_getElemLabel();
 389:                     $content[] = $this->_getElemField();
 390:                     $content[] = $this->_getElemHelp();
 391:                     $content[] = $this->_getElemScript();
 392:                     // / add this fields error message
 393:                     if (array_key_exists($this->get('idfield'), $errors)) {
 394:                         $error = $errors[$this->get('idfield')];
 395:                         $content[] = new cHTMLParagraph($error, 'pifa-error-message');
 396:                     }
 397:                 } catch (PifaNotImplementedException $e) {
 398:                     return NULL; // PASS // warning?
 399:                 }
 400: 
 401:                 $content = array_filter($content);
 402:                 if (empty($content)) {
 403:                     return NULL; // PASS // warning?
 404:                 }
 405: 
 406:                 // CSS class for surrounding division
 407:                 $class = 'pifa-field-' . $this->get('field_type');
 408:                 // optional class for field
 409:                 if (0 < strlen(trim($this->get('css_class')))) {
 410:                     $class .= ' ' . implode(' ', explode(',', $this->get('css_class')));
 411:                 }
 412:                 // optional class for obligatory field
 413:                 if (true === (bool) $this->get('obligatory')) {
 414:                     $class .= ' pifa-obligatory';
 415:                 }
 416:                 // optional error class for field
 417:                 if (NULL !== $error) {
 418:                     $class .= ' pifa-error';
 419:                 }
 420: 
 421:                 // ID for surrounding division
 422:                 $id = 'pifa-field-' . $this->get('idfield');
 423: 
 424:                 // surrounding division
 425:                 $div = new cHTMLDiv($content, $class, $id);
 426: 
 427:                 return "\n\t" . $div->render();
 428:                 break;
 429:         }
 430:     }
 431: 
 432:     /**
 433:      *
 434:      * @return cHTMLLabel
 435:      * @todo should be private, right?
 436:      */
 437:     public function _getElemLabel() {
 438:         if (1 !== cSecurity::toInteger($this->get('display_label'))) {
 439:             return '';
 440:         }
 441: 
 442:         // get field data
 443:         $idfield = cSecurity::toInteger($this->get('idfield'));
 444:         $fieldType = cSecurity::toInteger($this->get('field_type'));
 445:         $label = $this->get('label');
 446: 
 447:         if (NULL === $label) {
 448:             return NULL;
 449:         }
 450: 
 451:         // buttons have no external label
 452:         // the label is instead used as element value (see _getElemField())
 453:         if (in_array($fieldType, array(
 454:             self::BUTTONSUBMIT,
 455:             self::BUTTONRESET,
 456:             self::BUTTONBACK
 457:         ))) {
 458:             return NULL;
 459:         }
 460: 
 461:         // obligatory fields have an additional ' *'
 462:         if (true === (bool) $this->get('obligatory')) {
 463:             $label .= ' *';
 464:         }
 465: 
 466:         // add span to request new captcha code
 467:         // if (self::CAPTCHA===$fieldType) {
 468:         // $label .= '<br><br><span style="cursor: pointer;">New Captcha
 469:         // Code</span>';
 470:         // }
 471: 
 472:         $elemLabel = new cHTMLLabel($label, 'pifa-field-elm-' . $idfield, 'pifa-field-lbl');
 473:         // set ID (workaround: remove ID first!)
 474:         $elemLabel->removeAttribute('id');
 475: 
 476:         return $elemLabel;
 477:     }
 478: 
 479:     /**
 480:      * Creates the HTML for a form field.
 481:      *
 482:      * The displayed value of a form field can be set via a GET param whose name
 483:      * has to be the fields column name which is set if the form is displayed
 484:      * for the first time and user hasn't entered another value.
 485:      *
 486:      * @param boolean $error if field elem should be displayed as erroneous
 487:      * @throws PifaNotImplementedException if field type is not implemented
 488:      * @return cHTMLTextbox cHTMLTextarea cHTMLPasswordbox cHTMLSpan
 489:      *         cHTMLSelectElement NULL cHTMLButton
 490:      * @todo should be private, right?
 491:      */
 492:     public function _getElemField() {
 493: 
 494:         // get field data
 495:         $idfield = cSecurity::toInteger($this->get('idfield'));
 496: 
 497:         $fieldType = cSecurity::toInteger($this->get('field_type'));
 498: 
 499:         $columnName = $this->get('column_name');
 500: 
 501:         $label = $this->get('label');
 502: 
 503:         // get option labels & values
 504:         // either from field or from external data source class
 505:         $optionClass = $this->get('option_class');
 506:         if (0 === strlen(trim($optionClass))) {
 507:             $optionLabels = $this->get('option_labels');
 508:             if (NULL !== $optionLabels) {
 509:                 $optionLabels = explode(',', $optionLabels);
 510:             }
 511:             $optionValues = $this->get('option_values');
 512:             if (NULL !== $optionValues) {
 513:                 $optionValues = explode(',', $optionValues);
 514:             }
 515:         } else {
 516:             $filename = Pifa::fromCamelCase($optionClass);
 517:             $filename = "extensions/class.pifa.$filename.php";
 518:             if (false === file_exists(Pifa::getPath() . $filename)) {
 519:                 $msg = Pifa::i18n('MISSING_EOD_FILE');
 520:                 $msg = sprintf($msg, $filename);
 521:                 throw new PifaException($msg);
 522:             }
 523:             plugin_include(Pifa::getName(), $filename);
 524:             if (false === class_exists($optionClass)) {
 525:                 $msg = Pifa::i18n('MISSING_EOD_CLASS');
 526:                 $msg = sprintf($msg, $optionClass);
 527:                 throw new PifaException($msg);
 528:             }
 529:             $dataSource = new $optionClass();
 530:             $optionLabels = $dataSource->getOptionLabels();
 531:             $optionValues = $dataSource->getOptionValues();
 532:         }
 533: 
 534:         // ID for field & FOR for label
 535:         $id = 'pifa-field-elm-' . $idfield;
 536: 
 537:         // get current value
 538:         $value = $this->getValue();
 539: 
 540:         // if no current value is given
 541:         if (NULL === $value) {
 542:             // the fields default value is used
 543:             $value = $this->get('default_value');
 544:             // which could be overwritten by a GET param
 545:             if (array_key_exists($columnName, $_GET)) {
 546:                 $value = $_GET[$columnName];
 547:                 // try to prevent XSS ... the lazy way ...
 548:                 $value = htmlentities($value, ENT_COMPAT | ENT_HTML401, 'UTF-8');
 549:             }
 550:         }
 551: 
 552:         switch ($fieldType) {
 553: 
 554:             case self::INPUTTEXT:
 555: 
 556:                 $elemField = new cHTMLTextbox($columnName);
 557:                 // set ID (workaround: remove ID first!)
 558:                 $elemField->removeAttribute('id')->setID($id);
 559:                 // due to a bug setting NULL as title leads to title="title"
 560:                 if (!is_null($this->get('default_value'))) {
 561:                     $elemField->setAttribute('title', $this->get('default_value'));
 562:                 }
 563:                 if (!is_null($value)) {
 564:                     $elemField->setValue($value);
 565:                 }
 566:                 break;
 567: 
 568:             case self::TEXTAREA:
 569: 
 570:                 $elemField = new cHTMLTextarea($columnName);
 571:                 // set ID (workaround: remove ID first!)
 572:                 $elemField->removeAttribute('id')->setID($id);
 573:                 if (!is_null($this->get('default_value'))) {
 574:                     $elemField->setAttribute('title', $this->get('default_value'));
 575:                 }
 576:                 if (!is_null($value)) {
 577:                     $elemField->setValue($value);
 578:                 }
 579:                 break;
 580: 
 581:             case self::INPUTPASSWORD:
 582: 
 583:                 $elemField = new cHTMLPasswordbox($columnName);
 584:                 // set ID (workaround: remove ID first!)
 585:                 $elemField->removeAttribute('id')->setID($id);
 586:                 if (!is_null($this->get('default_value'))) {
 587:                     $elemField->setAttribute('title', $this->get('default_value'));
 588:                 }
 589:                 if (!is_null($value)) {
 590:                     $elemField->setValue($value);
 591:                 }
 592:                 break;
 593: 
 594:             case self::INPUTRADIO:
 595:             case self::INPUTCHECKBOX:
 596: 
 597:                 $count = min(array(
 598:                     count($optionLabels),
 599:                     count($optionValues)
 600:                 ));
 601:                 $tmpHtml = '';
 602:                 for ($i = 0; $i < $count; $i++) {
 603:                     if (self::INPUTRADIO === $fieldType) {
 604:                         $elemField = new cHTMLRadiobutton($columnName, $optionValues[$i]);
 605:                     } else if (self::INPUTCHECKBOX === $fieldType) {
 606:                         $elemField = new cHTMLCheckbox($columnName . '[]', $optionValues[$i]);
 607:                     }
 608:                     if (!is_array($value)) {
 609:                         $value = explode(',', $value);
 610:                     }
 611:                     $elemField->setChecked(in_array($optionValues[$i], $value));
 612:                     $elemField->setLabelText($optionLabels[$i]);
 613:                     $tmpHtml .= $elemField->render();
 614:                 }
 615:                 $elemField = new cHTMLSpan($tmpHtml);
 616:                 break;
 617: 
 618:             case self::SELECT:
 619:             case self::SELECTMULTI:
 620: 
 621:                 $elemField = new cHTMLSelectElement($columnName);
 622: 
 623:                 // set ID (workaround: remove ID first!)
 624:                 $elemField->removeAttribute('id')->setID($id);
 625:                 $autofill = array();
 626:                 $count = min(array(
 627:                     count($optionLabels),
 628:                     count($optionValues)
 629:                 ));
 630: 
 631:                 for ($i = 0; $i < $count; $i++) {
 632:                     $autofill[$optionValues[$i]] = $optionLabels[$i];
 633:                 }
 634: 
 635:                 $elemField->autoFill($autofill);
 636:                 $elemField->setDefault($value);
 637: 
 638:                 break;
 639: 
 640:             case self::DATEPICKER:
 641: 
 642:                 // hidden field to post date in generic date format
 643:                 $hiddenField = new cHTMLHiddenField($columnName);
 644:                 $hiddenField->removeAttribute('id')->setID($id . '-hidden');
 645:                 if (!is_null($value)) {
 646:                     $hiddenField->setValue($value);
 647:                 }
 648: 
 649:                 // textbox to display date in localized date format
 650:                 $textbox = new cHTMLTextbox($columnName . '_visible');
 651:                 // set ID (workaround: remove ID first!)
 652:                 $textbox->removeAttribute('id')->setID($id);
 653: 
 654:                 // surrounding div
 655:                 $elemField = new cHTMLDiv(array(
 656:                     $hiddenField,
 657:                     $textbox
 658:                 ));
 659: 
 660:                 break;
 661: 
 662:             case self::INPUTFILE:
 663: 
 664:                 $elemField = new cHTMLUpload($columnName);
 665:                 // set ID (workaround: remove ID first!)
 666:                 $elemField->removeAttribute('id')->setID($id);
 667:                 break;
 668: 
 669:             case self::PROCESSBAR:
 670: 
 671:                 $elemField = NULL;
 672:                 // TODO PROCESSBAR is NYI
 673:                 // $elemField = new cHTML();
 674:                 break;
 675: 
 676:             case self::SLIDER:
 677: 
 678:                 $elemField = NULL;
 679:                 // TODO SLIDER is NYI
 680:                 // $elemField = new cHTML();
 681:                 break;
 682: 
 683:             // case self::CAPTCHA:
 684: 
 685:             // // input
 686:             // $elemField = new cHTMLTextbox($columnName);
 687:             // // set ID (workaround: remove ID first!)
 688:             // $elemField->removeAttribute('id')->setID($id);
 689:             // if (NULL !== $value) {
 690:             // $elemField->setValue($value);
 691:             // }
 692: 
 693:             // // surrounding div
 694:             // // img src (front_content.php?securimage) will be caught by
 695:             // // Pifa::afterLoadPlugins
 696:             // $elemField = new cHTMLDiv(array(
 697:             // new cHTMLImage('front_content.php?securimage'),
 698:             // $elemField
 699:             // ));
 700: 
 701:             // break;
 702: 
 703:             case self::BUTTONSUBMIT:
 704:             case self::BUTTONRESET:
 705:             case self::BUTTONBACK:
 706: 
 707:                 $modes = array(
 708:                     self::BUTTONSUBMIT => 'submit',
 709:                     self::BUTTONRESET => 'reset',
 710:                     self::BUTTONBACK => 'button'
 711:                 );
 712:                 $elemField = new cHTMLButton($columnName);
 713:                 // set ID (workaround: remove ID first!)
 714:                 $elemField->removeAttribute('id')->setID($id);
 715:                 if (NULL !== $label) {
 716:                     $elemField->setTitle($label);
 717:                 } else {
 718:                     $elemField->setTitle($modes[$fieldType]);
 719:                 }
 720:                 $elemField->setMode($modes[$fieldType]);
 721:                 break;
 722: 
 723:             case self::MATRIX:
 724: 
 725:                 $elemField = NULL;
 726:                 // TODO MATRIX is NYI
 727:                 // $elemField = new cHTML();
 728:                 break;
 729: 
 730:             case self::PARA:
 731:                 $elemField = NULL;
 732:                 // TODO PARA is NYI
 733:                 // $elemField = new cHTML();
 734:                 break;
 735: 
 736:             case self::INPUTHIDDEN:
 737:                 $elemField = new cHTMLHiddenField($columnName);
 738:                 // set ID (workaround: remove ID first!)
 739:                 $elemField->removeAttribute('id')->setID($id);
 740:                 if (NULL !== $value) {
 741:                     $elemField->setValue($value);
 742:                 }
 743:                 break;
 744: 
 745:             default:
 746:                 $msg = Pifa::i18n('NOT_IMPLEMENTED_FIELDTYPE');
 747:                 $msg = sprintf($msg, $fieldType);
 748:                 throw new PifaNotImplementedException($msg);
 749:         }
 750: 
 751:         return $elemField;
 752:     }
 753: 
 754:     /**
 755:      *
 756:      * @return Ambigous <NULL, cHTMLParagraph>
 757:      * @todo should be private, right?
 758:      */
 759:     public function _getElemHelp() {
 760:         $helpText = $this->get('help_text');
 761: 
 762:         $p = NULL;
 763:         if (0 < strlen($helpText)) {
 764:             $p = new cHTMLParagraph($helpText, 'pifa-field-help');
 765:         }
 766: 
 767:         return $p;
 768:     }
 769: 
 770:     /**
 771:      *
 772:      * @return Ambigous <NULL, cHTMLScript>
 773:      * @todo should be private, right?
 774:      */
 775:     public function _getElemScript() {
 776: 
 777:         // ID for field & FOR for label
 778:         $idfield = cSecurity::toInteger($this->get('idfield'));
 779:         $fieldType = cSecurity::toInteger($this->get('field_type'));
 780: 
 781:         switch ($fieldType) {
 782:             case self::DATEPICKER:
 783:                 $sel = '#pifa-field-elm-' . $idfield;
 784:                 // dateFormat: 'yy-mm-dd', // could be different
 785:                 // altFormat as ISO_8601
 786:                 $script = "jQuery(function(){ jQuery('$sel').datepicker({
 787:                     altFormat: 'yy-mm-dd',
 788:                     altField: '$sel-hidden'
 789:                 });});";
 790:                 break;
 791:             // case self::CAPTCHA:
 792:             // $sel = '#pifa-field-' . $idfield . ' label';
 793:             // $newCaptchaCode = mi18n("NEW_CAPTCHA_CODE");
 794:             // $script = "jQuery(function(){\n";
 795:             // // implement captcha reload on click
 796:             // $script .= "jQuery('$sel').click(function (e) {\n";
 797:             // $script .= "e.preventDefault();\n";
 798:             // $script .= "var url = 'front_content.php?securimage&' +
 799:             // Math.random();\n";
 800:             // $script .= "jQuery(this).parent().find('img').attr('src',
 801:             // url);\n";
 802:             // $script .= "});\n";
 803:             // // append 'New Captcha Code' to label
 804:             // $script .= "jQuery('$sel').append('<br/><br/><span
 805:             // style=\"cursor:pointer\">$newCaptchaCode</span>');";
 806:             // $script .= "});\n";
 807:             // break;
 808:             default:
 809:                 $script = '';
 810:         }
 811: 
 812:         $elemScript = NULL;
 813:         if (0 < strlen($script)) {
 814:             $elemScript = new cHTMLScript();
 815:             $elemScript->setContent($script);
 816:         }
 817: 
 818:         return $elemScript;
 819:     }
 820: 
 821:     /**
 822:      *
 823:      * @param int $fieldType
 824:      * @todo add different icons for different form field types
 825:      */
 826:     public static function getFieldTypeIcon($fieldType) {
 827:         switch ($fieldType) {
 828:             case self::INPUTTEXT:
 829:             case self::TEXTAREA:
 830:             case self::INPUTPASSWORD:
 831:             case self::INPUTRADIO:
 832:             case self::INPUTCHECKBOX:
 833:             case self::SELECT:
 834:             case self::SELECTMULTI:
 835:             case self::DATEPICKER:
 836:             case self::INPUTFILE:
 837:             case self::PROCESSBAR:
 838:             case self::SLIDER:
 839:             // case self::CAPTCHA:
 840:             case self::BUTTONSUBMIT:
 841:             case self::BUTTONRESET:
 842:             case self::BUTTONBACK:
 843:             case self::MATRIX:
 844:             case self::PARA:
 845:             case self::INPUTHIDDEN:
 846:             case self::FIELDSET_BEGIN:
 847:             case self::FIELDSET_END:
 848:                 return 'icon.png';
 849:         }
 850:     }
 851: 
 852:     /**
 853:      * Returns an array containing all field type ids.
 854:      *
 855:      * @return array
 856:      */
 857:     public static function getFieldTypeIds() {
 858:         return array_keys(self::getFieldTypeNames());
 859:     }
 860: 
 861:     /**
 862:      * Returns an array containing all field type ids mapped to their names.
 863:      *
 864:      * @return array
 865:      */
 866:     public static function getFieldTypeNames() {
 867:         return array(
 868:             self::INPUTTEXT => Pifa::i18n('INPUTTEXT'),
 869:             self::TEXTAREA => Pifa::i18n('TEXTAREA'),
 870:             self::INPUTPASSWORD => Pifa::i18n('INPUTPASSWORD'),
 871:             self::INPUTRADIO => Pifa::i18n('INPUTRADIO'),
 872:             self::INPUTCHECKBOX => Pifa::i18n('INPUTCHECKBOX'),
 873:             self::SELECT => Pifa::i18n('SELECT'),
 874:             self::SELECTMULTI => Pifa::i18n('SELECTMULTI'),
 875:             self::DATEPICKER => Pifa::i18n('DATEPICKER'),
 876:             self::INPUTFILE => Pifa::i18n('INPUTFILE'),
 877:             self::PROCESSBAR => Pifa::i18n('PROCESSBAR'),
 878:             self::SLIDER => Pifa::i18n('SLIDER'),
 879:             // self::CAPTCHA => Pifa::i18n('CAPTCHA'),
 880:             self::BUTTONSUBMIT => Pifa::i18n('BUTTONSUBMIT'),
 881:             self::BUTTONRESET => Pifa::i18n('BUTTONRESET'),
 882:             self::BUTTONBACK => Pifa::i18n('BUTTONBACK'),
 883:             // self::MATRIX => Pifa::i18n('MATRIX'),
 884:             self::PARA => Pifa::i18n('PARAGRAPH'),
 885:             self::INPUTHIDDEN => Pifa::i18n('INPUTHIDDEN'),
 886:             self::FIELDSET_BEGIN => Pifa::i18n('FIELDSET_BEGIN'),
 887:             self::FIELDSET_END => Pifa::i18n('FIELDSET_END')
 888:         );
 889:     }
 890: 
 891:     /**
 892:      * Return the field type name for the given field type id.
 893:      *
 894:      * @param int $fieldType
 895:      * @return string
 896:      */
 897:     public static function getFieldTypeName($fieldTypeId) {
 898:         $fieldTypeId = cSecurity::toInteger($fieldTypeId);
 899:         $fieldTypeNames = self::getFieldTypeNames();
 900: 
 901:         if (array_key_exists($fieldTypeId, $fieldTypeNames)) {
 902:             $fieldTypeName = $fieldTypeNames[$fieldTypeId];
 903:         } else {
 904:             $fieldTypeName = Pifa::i18n('UNKNOWN');
 905:         }
 906: 
 907:         return $fieldTypeName;
 908:     }
 909: 
 910:     /**
 911:      * Return this fields type name.
 912:      *
 913:      * @param int $fieldType
 914:      * @return string
 915:      */
 916:     public function getMyFieldTypeName() {
 917:         return self::getFieldTypeName($this->get('field_type'));
 918:     }
 919: 
 920:     /**
 921:      * Returns a string describing this fields database data type as used in
 922:      * MySQL CREATE and ALTER TABLE statements.
 923:      *
 924:      * @throws PifaException if field is not loaded
 925:      * @throws PifaException if field type is not implemented
 926:      */
 927:     public function getDbDataType() {
 928:         if (!$this->isLoaded()) {
 929:             $msg = Pifa::i18n('FIELD_LOAD_ERROR');
 930:             throw new PifaException($msg);
 931:         }
 932: 
 933:         $fieldType = cSecurity::toInteger($this->get('field_type'));
 934: 
 935:         switch ($fieldType) {
 936: 
 937:             // Text and password input fields can store a string of
 938:             // arbitrary length. Cause they are single lined it does not
 939:             // make sense to enable them storing more than 1023 characters
 940:             // though.
 941:             case self::INPUTTEXT:
 942:             case self::INPUTPASSWORD:
 943:             case self::INPUTHIDDEN:
 944:             case self::INPUTFILE:
 945: 
 946:                 return 'VARCHAR(' . self::VARCHAR_SIZE . ')';
 947: 
 948:             // A group of checkboxes can store multiple values. So this has
 949:             // to be implemented as a CSV string of max. 1023 characters.
 950:             case self::INPUTCHECKBOX:
 951: 
 952:                 return 'VARCHAR(' . self::VARCHAR_SIZE . ')';
 953: 
 954:             // Textareas are designed to store longer texts so I chose the
 955:             // TEXT data type to enable them storing up to 65535 characters.
 956:             case self::TEXTAREA:
 957: 
 958:                 return 'TEXT';
 959: 
 960:             // A group of radiobuttons or a select box can store a single
 961:             // value of a given set of options. This can be implemented
 962:             // as an enumeration.
 963:             case self::INPUTRADIO:
 964:             case self::SELECT:
 965:             case self::SELECTMULTI:
 966: 
 967:                 // $optionValues = $this->get('option_values');
 968:                 // $optionValues = explode(',', $optionValues);
 969:                 // array_map(function ($val) {
 970:                 // return "'$val'";
 971:                 // }, $optionValues);
 972:                 // $optionValues = join(',', $optionValues);
 973: 
 974:                 // return "ENUM($optionValues)";
 975: 
 976:                 // as long as the GUI does not offer an entry to define option
 977:                 // values when creating a new field assume VARCHAR as data type
 978:                 return 'VARCHAR(' . self::VARCHAR_SIZE . ')';
 979: 
 980:             // The datepicker can store a date having an optional time
 981:             // portion. I chose DATETIME as data type over TIMESTAMP due to
 982:             // its limitation of storing dates before 1970-01-01 although
 983:             // even DATETIME can't store dates before 1000-01-01.
 984:             case self::DATEPICKER:
 985: 
 986:                 return 'DATETIME';
 987: 
 988:             // Buttons don't have any values that should be stored.
 989:             case self::BUTTONSUBMIT:
 990:             case self::BUTTONRESET:
 991:             case self::BUTTONBACK:
 992: 
 993:                 return NULL;
 994: 
 995:             // TODO For some filed types I havn't yet decided which data
 996:             // type to use.
 997:             case self::PROCESSBAR:
 998:             case self::SLIDER:
 999:             // case self::CAPTCHA:
1000:             case self::MATRIX:
1001:             case self::PARA:
1002:             case self::FIELDSET_BEGIN:
1003:             case self::FIELDSET_END:
1004: 
1005:                 return NULL;
1006: 
1007:             default:
1008:                 $msg = Pifa::i18n('NOT_IMPLEMENTED_FIELDTYPE');
1009:                 $msg = sprintf($msg, $fieldType);
1010:                 throw new PifaException($msg);
1011:         }
1012:     }
1013: 
1014:     /**
1015:      * Deletes this form with all its fields and stored data.
1016:      * The forms data table is also dropped.
1017:      */
1018:     public function delete() {
1019:         $cfg = cRegistry::getConfig();
1020:         $db = cRegistry::getDb();
1021: 
1022:         if (!$this->isLoaded()) {
1023:             $msg = Pifa::i18n('FIELD_LOAD_ERROR');
1024:             throw new PifaException($msg);
1025:         }
1026: 
1027:         // update ranks of younger siblings
1028:         $sql = "-- PifaField->delete()
1029:             UPDATE
1030:                 " . cRegistry::getDbTableName('pifa_field') . "
1031:             SET
1032:                 field_rank = field_rank - 1
1033:             WHERE
1034:                 idform = " . cSecurity::toInteger($this->get('idform')) . "
1035:                 AND field_rank > " . cSecurity::toInteger($this->get('field_rank')) . "
1036:             ;";
1037:         if (false === $db->query($sql)) {
1038:             // false is returned if no fields were updated
1039:             // but that doesn't matter ...
1040:         }
1041: 
1042:         // delete field
1043:         $sql = "-- PifaField->delete()
1044:             DELETE FROM
1045:                 " . cRegistry::getDbTableName('pifa_field') . "
1046:             WHERE
1047:                 idfield = " . cSecurity::toInteger($this->get('idfield')) . "
1048:             ;";
1049:         if (false === $db->query($sql)) {
1050:             $msg = Pifa::i18n('FIELD_DELETE_ERROR');
1051:             throw new PifaException($msg);
1052:         }
1053: 
1054:         // drop column of data table
1055:         if (0 < strlen(trim($this->get('column_name')))) {
1056:             $pifaForm = new PifaForm($this->get('idform'));
1057: 
1058:             if (0 < strlen(trim($pifaForm->get('data_table')))) {
1059:                 $sql = "-- PifaField->delete()
1060:                     ALTER TABLE
1061:                         `" . cSecurity::toString($pifaForm->get('data_table')) . "`
1062:                     DROP COLUMN
1063:                         `" . cSecurity::toString($this->get('column_name')) . "`
1064:                     ;";
1065:                 if (false === $db->query($sql)) {
1066:                     $msg = Pifa::i18n('COLUMN_DROP_ERROR');
1067:                     throw new PifaException($msg);
1068:                 }
1069:             }
1070:         }
1071:     }
1072: 
1073:     /**
1074:      * Determines for which form field types which data should be editable in
1075:      * backend.
1076:      *
1077:      * @param string $columnName for data to edit
1078:      */
1079:     public function showField($columnName) {
1080:         $fieldType = $this->get('field_type');
1081:         $fieldType = cSecurity::toInteger($fieldType);
1082: 
1083:         switch ($columnName) {
1084: 
1085:             case 'idfield':
1086:             case 'idform':
1087:             case 'field_rank':
1088:             case 'field_type':
1089:                 // will never be editable directly
1090:                 return false;
1091: 
1092:             case 'column_name':
1093:                 return in_array($fieldType, array(
1094:                     self::INPUTTEXT,
1095:                     self::TEXTAREA,
1096:                     self::INPUTPASSWORD,
1097:                     self::INPUTRADIO,
1098:                     self::INPUTCHECKBOX,
1099:                     self::SELECT,
1100:                     self::SELECTMULTI,
1101:                     self::DATEPICKER,
1102:                     self::INPUTFILE,
1103:                     self::PROCESSBAR,
1104:                     self::SLIDER,
1105:                     // self::CAPTCHA,
1106:                     // self::BUTTONSUBMIT,
1107:                     // self::BUTTONRESET,
1108:                     // self::BUTTONBACK,
1109:                     self::MATRIX,
1110:                     self::INPUTHIDDEN
1111:                     /*
1112:                     self::FIELDSET_BEGIN,
1113:                     self::FIELDSET_END
1114:                     */
1115:                 ));
1116: 
1117:             case 'label':
1118:             case 'display_label':
1119:                 return in_array($fieldType, array(
1120:                     self::INPUTTEXT,
1121:                     self::TEXTAREA,
1122:                     self::INPUTPASSWORD,
1123:                     self::INPUTRADIO,
1124:                     self::INPUTCHECKBOX,
1125:                     self::SELECT,
1126:                     self::SELECTMULTI,
1127:                     self::DATEPICKER,
1128:                     self::INPUTFILE,
1129:                     self::PROCESSBAR,
1130:                     self::SLIDER,
1131:                     // self::CAPTCHA,
1132:                     self::BUTTONSUBMIT,
1133:                     self::BUTTONRESET,
1134:                     self::BUTTONBACK,
1135:                     self::MATRIX,
1136:                     self::PARA,
1137:                     // self::INPUTHIDDEN,
1138:                     self::FIELDSET_BEGIN
1139:                     /*
1140:                     self::FIELDSET_END
1141:                     */
1142:                     ));
1143: 
1144:             case 'default_value':
1145:                 return in_array($fieldType, array(
1146:                     self::INPUTTEXT,
1147:                     self::TEXTAREA,
1148:                     self::INPUTPASSWORD,
1149:                     self::INPUTRADIO,
1150:                     self::INPUTCHECKBOX,
1151:                     self::SELECT,
1152:                     self::SELECTMULTI,
1153:                     self::DATEPICKER,
1154:                     self::INPUTFILE,
1155:                     self::PROCESSBAR,
1156:                     self::SLIDER,
1157:                     // self::CAPTCHA,
1158:                     self::BUTTONSUBMIT,
1159:                     self::BUTTONRESET,
1160:                     self::BUTTONBACK,
1161:                     self::MATRIX,
1162:                     self::INPUTHIDDEN
1163:                 ));
1164: 
1165:             case 'option_labels':
1166:             case 'option_values':
1167:             case 'option_class':
1168:                 return in_array($fieldType, array(
1169:                     self::INPUTRADIO,
1170:                     self::INPUTCHECKBOX,
1171:                     self::SELECT,
1172:                     self::SELECTMULTI
1173:                 ));
1174: 
1175:             case 'help_text':
1176:                 return in_array($fieldType, array(
1177:                     self::INPUTTEXT,
1178:                     self::TEXTAREA,
1179:                     self::INPUTPASSWORD,
1180:                     self::INPUTRADIO,
1181:                     self::INPUTCHECKBOX,
1182:                     self::SELECT,
1183:                     self::SELECTMULTI,
1184:                     self::DATEPICKER,
1185:                     self::INPUTFILE,
1186:                     self::PROCESSBAR,
1187:                     self::SLIDER,
1188:                     // self::CAPTCHA,
1189:                     self::BUTTONSUBMIT,
1190:                     self::BUTTONRESET,
1191:                     self::BUTTONBACK,
1192:                     self::MATRIX,
1193:                     self::PARA,
1194:                     self::FIELDSET_BEGIN
1195:                 ));
1196: 
1197:             case 'obligatory':
1198:                 return in_array($fieldType, array(
1199:                     self::INPUTTEXT,
1200:                     self::TEXTAREA,
1201:                     self::INPUTPASSWORD,
1202:                     self::INPUTRADIO,
1203:                     self::INPUTCHECKBOX,
1204:                     self::SELECT,
1205:                     self::SELECTMULTI,
1206:                     self::DATEPICKER,
1207:                     self::INPUTFILE,
1208:                     self::PROCESSBAR,
1209:                     self::SLIDER,
1210:                     // self::CAPTCHA,
1211:                     // self::BUTTONSUBMIT,
1212:                     // self::BUTTONRESET,
1213:                     // self::BUTTONBACK,
1214:                     self::MATRIX,
1215:                     self::INPUTHIDDEN
1216:                 ));
1217: 
1218:             case 'rule':
1219:                 return in_array($fieldType, array(
1220:                     self::INPUTTEXT,
1221:                     self::TEXTAREA,
1222:                     self::INPUTPASSWORD,
1223:                     self::INPUTRADIO,
1224:                     self::INPUTCHECKBOX,
1225:                     self::SELECT,
1226:                     self::SELECTMULTI,
1227:                     self::DATEPICKER,
1228:                     self::INPUTFILE,
1229:                     self::PROCESSBAR,
1230:                     self::SLIDER,
1231:                     // self::CAPTCHA,
1232:                     // self::BUTTONSUBMIT,
1233:                     // self::BUTTONRESET,
1234:                     // self::BUTTONBACK,
1235:                     self::MATRIX,
1236:                     self::INPUTHIDDEN
1237:                 ));
1238: 
1239:             case 'error_message':
1240:                 return in_array($fieldType, array(
1241:                     self::INPUTTEXT,
1242:                     self::TEXTAREA,
1243:                     self::INPUTPASSWORD,
1244:                     self::INPUTRADIO,
1245:                     self::INPUTCHECKBOX,
1246:                     self::SELECT,
1247:                     self::SELECTMULTI,
1248:                     self::DATEPICKER,
1249:                     self::INPUTFILE,
1250:                     self::PROCESSBAR,
1251:                     self::SLIDER,
1252:                     // self::CAPTCHA,
1253:                     // self::BUTTONSUBMIT,
1254:                     // self::BUTTONRESET,
1255:                     // self::BUTTONBACK,
1256:                     self::MATRIX,
1257:                     self::INPUTHIDDEN
1258:                 ));
1259: 
1260:             case 'css_class':
1261:                 return in_array($fieldType, array(
1262:                     self::INPUTTEXT,
1263:                     self::TEXTAREA,
1264:                     self::INPUTPASSWORD,
1265:                     self::INPUTRADIO,
1266:                     self::INPUTCHECKBOX,
1267:                     self::SELECT,
1268:                     self::SELECTMULTI,
1269:                     self::DATEPICKER,
1270:                     self::INPUTFILE,
1271:                     self::PROCESSBAR,
1272:                     self::SLIDER,
1273:                     // self::CAPTCHA,
1274:                     self::BUTTONSUBMIT,
1275:                     self::BUTTONRESET,
1276:                     self::BUTTONBACK,
1277:                     self::MATRIX,
1278:                     self::PARA,
1279:                     self::FIELDSET_BEGIN
1280:                     /*
1281:                     self::INPUTHIDDEN
1282:                     */
1283:                 ));
1284: 
1285:             default:
1286:                 $msg = Pifa::i18n('NOT_IMPLEMENTED_FIELDPROP');
1287:                 $msg = sprintf($msg, $columnName);
1288:                 throw new PifaException($msg);
1289:         }
1290:     }
1291: 
1292:     /**
1293:      *
1294:      * @return array
1295:      */
1296:     public function getOptions() {
1297:         $option_labels = $this->get('option_labels');
1298:         $option_values = $this->get('option_values');
1299: 
1300:         $out = array();
1301:         if (0 < strlen($option_labels . $option_values)) {
1302:             $option_labels = explode(',', $option_labels);
1303:             $option_values = explode(',', $option_values);
1304: 
1305:             // str_getcsv requires PHP 5.3 :(
1306:             // $option_labels = str_getcsv($option_labels);
1307:             // $option_values = str_getcsv($option_values);
1308: 
1309:             // instead replace commas stored as entities by real commas
1310:             $func = create_function('$v', 'return str_replace(\'&#44;\', \',\', $v);');
1311:             $option_labels = array_map($func, $option_labels);
1312:             $option_values = array_map($func, $option_values);
1313: 
1314:             foreach (array_keys($option_labels) as $key) {
1315:                 $out[] = array(
1316:                     'label' => $option_labels[$key],
1317:                     'value' => $option_values[$key]
1318:                 );
1319:             }
1320:         }
1321: 
1322:         return $out;
1323:     }
1324: }
1325: 
1326: ?>
CMS CONTENIDO 4.9.1 API documentation generated by ApiGen 2.8.0