Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.
   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  
  18  /**
  19   * select type form element
  20   *
  21   * Contains HTML class for a select type element
  22   *
  23   * @package   core_form
  24   * @copyright 2006 Jamie Pratt <me@jamiep.org>
  25   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  26   */
  27  
  28  require_once('HTML/QuickForm/select.php');
  29  require_once ('templatable_form_element.php');
  30  
  31  /**
  32   * select type form element
  33   *
  34   * HTML class for a select type element
  35   *
  36   * @package   core_form
  37   * @category  form
  38   * @copyright 2006 Jamie Pratt <me@jamiep.org>
  39   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  40   */
  41  class MoodleQuickForm_select extends HTML_QuickForm_select implements templatable {
  42  
  43      use templatable_form_element {
  44          export_for_template as export_for_template_base;
  45      }
  46  
  47      /** @var string html for help button, if empty then no help */
  48      var $_helpbutton='';
  49  
  50      /** @var bool if true label will be hidden */
  51      var $_hiddenLabel=false;
  52  
  53      /**
  54       * constructor
  55       *
  56       * @param string $elementName Select name attribute
  57       * @param mixed $elementLabel Label(s) for the select
  58       * @param mixed $options Data to be used to populate options
  59       * @param mixed $attributes Either a typical HTML attribute string or an associative array
  60       */
  61      public function __construct($elementName=null, $elementLabel=null, $options=null, $attributes=null) {
  62          parent::__construct($elementName, $elementLabel, $options, $attributes);
  63      }
  64  
  65      /**
  66       * Old syntax of class constructor. Deprecated in PHP7.
  67       *
  68       * @deprecated since Moodle 3.1
  69       */
  70      public function MoodleQuickForm_select($elementName=null, $elementLabel=null, $options=null, $attributes=null) {
  71          debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
  72          self::__construct($elementName, $elementLabel, $options, $attributes);
  73      }
  74  
  75      /**
  76       * Sets label to be hidden
  77       *
  78       * @param bool $hiddenLabel sets if label should be hidden
  79       */
  80      function setHiddenLabel($hiddenLabel){
  81          $this->_hiddenLabel = $hiddenLabel;
  82      }
  83  
  84      /**
  85       * Returns HTML for select form element.
  86       *
  87       * @return string
  88       */
  89      function toHtml(){
  90          $html = '';
  91          if ($this->getMultiple()) {
  92              // Adding an hidden field forces the browser to send an empty data even though the user did not
  93              // select any element. This value will be cleaned up in self::exportValue() as it will not be part
  94              // of the select options.
  95              $html .= '<input type="hidden" name="'.$this->getName().'" value="_qf__force_multiselect_submission">';
  96          }
  97          if ($this->_hiddenLabel){
  98              $this->_generateId();
  99              $html .= '<label class="accesshide" for="'.$this->getAttribute('id').'" >'.$this->getLabel().'</label>';
 100          }
 101          $html .= parent::toHtml();
 102          return $html;
 103      }
 104  
 105      /**
 106       * get html for help button
 107       *
 108       * @return string html for help button
 109       */
 110      function getHelpButton(){
 111          return $this->_helpbutton;
 112      }
 113  
 114      /**
 115       * Removes an OPTION from the SELECT
 116       *
 117       * @param string $value Value for the OPTION to remove
 118       * @return void
 119       */
 120      function removeOption($value)
 121      {
 122          $key=array_search($value, $this->_values);
 123          if ($key!==FALSE and $key!==null) {
 124              unset($this->_values[$key]);
 125          }
 126          foreach ($this->_options as $key=>$option){
 127              if ($option['attr']['value']==$value){
 128                  unset($this->_options[$key]);
 129                  // we must reindex the options because the ugly code in quickforms' select.php expects that keys are 0,1,2,3... !?!?
 130                  $this->_options = array_merge($this->_options);
 131                  return;
 132              }
 133          }
 134      }
 135  
 136      /**
 137       * Removes all OPTIONs from the SELECT
 138       */
 139      function removeOptions()
 140      {
 141          $this->_options = array();
 142      }
 143  
 144      /**
 145       * Slightly different container template when frozen. Don't want to use a label tag
 146       * with a for attribute in that case for the element label but instead use a div.
 147       * Templates are defined in renderer constructor.
 148       *
 149       * @return string
 150       */
 151      function getElementTemplateType(){
 152          if ($this->_flagFrozen){
 153              return 'static';
 154          } else {
 155              return 'default';
 156          }
 157      }
 158  
 159     /**
 160      * We check the options and return only the values that _could_ have been
 161      * selected. We also return a scalar value if select is not "multiple"
 162      *
 163      * @param array $submitValues submitted values
 164      * @param bool $assoc if true the retured value is associated array
 165      * @return mixed
 166      */
 167      function exportValue(&$submitValues, $assoc = false)
 168      {
 169          $emptyvalue = $this->getMultiple() ? [] : null;
 170          if (empty($this->_options)) {
 171              return $this->_prepareValue($emptyvalue, $assoc);
 172          }
 173  
 174          $value = $this->_findValue($submitValues);
 175          if (is_null($value)) {
 176              $value = $this->getValue();
 177          }
 178          $value = (array)$value;
 179  
 180          $cleaned = array();
 181          foreach ($value as $v) {
 182              foreach ($this->_options as $option) {
 183                  if ((string)$option['attr']['value'] === (string)$v) {
 184                      $cleaned[] = (string)$option['attr']['value'];
 185                      break;
 186                  }
 187              }
 188          }
 189  
 190          if (empty($cleaned)) {
 191              return $this->_prepareValue($emptyvalue, $assoc);
 192          }
 193          if ($this->getMultiple()) {
 194              return $this->_prepareValue($cleaned, $assoc);
 195          } else {
 196              return $this->_prepareValue($cleaned[0], $assoc);
 197          }
 198      }
 199  
 200      public function export_for_template(renderer_base $output) {
 201          $context = $this->export_for_template_base($output);
 202  
 203          $options = [];
 204          // Standard option attributes.
 205          $standardoptionattributes = ['text', 'value', 'selected', 'disabled'];
 206          foreach ($this->_options as $option) {
 207              if (is_array($this->_values) && in_array( (string) $option['attr']['value'], $this->_values)) {
 208                  $this->_updateAttrArray($option['attr'], ['selected' => 'selected']);
 209              }
 210              $o = [
 211                  'text' => $option['text'],
 212                  'value' => $option['attr']['value'],
 213                  'selected' => !empty($option['attr']['selected']),
 214                  'disabled' => !empty($option['attr']['disabled']),
 215              ];
 216              // Set other attributes.
 217              $otheroptionattributes = [];
 218              foreach ($option['attr'] as $attr => $value) {
 219                  if (!in_array($attr, $standardoptionattributes) && $attr != 'class' && !is_object($value)) {
 220                      $otheroptionattributes[] = $attr . '="' . s($value) . '"';
 221                  }
 222              }
 223              $o['optionattributes'] = implode(' ', $otheroptionattributes);
 224              $options[] = $o;
 225          }
 226          $context['options'] = $options;
 227          $context['nameraw'] = $this->getName();
 228  
 229          return $context;
 230      }
 231  }