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