Overview

Packages

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

Classes

  • cContentTypePifaForm
  • DefaultFormModule
  • DefaultFormProcessor
  • ExampleOptionsDatasource
  • MailedFormProcessor
  • Pifa
  • PifaAbstractFormModule
  • PifaAbstractFormProcessor
  • PifaAjaxHandler
  • PifaExporter
  • PifaExternalOptionsDatasourceInterface
  • PifaField
  • PifaFieldCollection
  • PifaForm
  • PifaFormCollection
  • PifaImporter
  • PifaLeftBottomPage
  • PifaRightBottomFormDataPage
  • PifaRightBottomFormExportPage
  • PifaRightBottomFormFieldsPage
  • PifaRightBottomFormImportPage
  • PifaRightBottomFormPage

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