[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/inc/Form/ -> DropdownElement.php (source)

   1  <?php
   2  
   3  namespace dokuwiki\Form;
   4  
   5  /**
   6   * Class DropdownElement
   7   *
   8   * Represents a HTML select. Please not that prefilling with input data only works for single values.
   9   *
  10   * @package dokuwiki\Form
  11   */
  12  class DropdownElement extends InputElement
  13  {
  14      /** @var array OptGroup[] */
  15      protected $optGroups = [];
  16  
  17      /** @var string[] the currently set values */
  18      protected $values = [];
  19  
  20      /**
  21       * @param string $name The name of this form element
  22       * @param array $options The available options
  23       * @param string $label The label text for this element (will be autoescaped)
  24       */
  25      public function __construct($name, $options, $label = '')
  26      {
  27          parent::__construct('dropdown', $name, $label);
  28          $this->rmattr('type');
  29          $this->optGroups[''] = new OptGroup(null, $options);
  30          $this->val('');
  31      }
  32  
  33      /**
  34       * Add an `<optgroup>` and respective options
  35       *
  36       * @param string $label
  37       * @param array $options
  38       * @return OptGroup a reference to the added optgroup
  39       * @throws \InvalidArgumentException
  40       */
  41      public function addOptGroup($label, $options)
  42      {
  43          if (empty($label)) {
  44              throw new \InvalidArgumentException(hsc('<optgroup> must have a label!'));
  45          }
  46          $this->optGroups[$label] = new OptGroup($label, $options);
  47          return end($this->optGroups);
  48      }
  49  
  50      /**
  51       * Set or get the optgroups of an Dropdown-Element.
  52       *
  53       * optgroups have to be given as associative array
  54       *   * the key being the label of the group
  55       *   * the value being an array of options as defined in @param null|array $optGroups
  56       * @return OptGroup[]|DropdownElement
  57       * @see OptGroup::options()
  58       *
  59       */
  60      public function optGroups($optGroups = null)
  61      {
  62          if ($optGroups === null) {
  63              return $this->optGroups;
  64          }
  65          if (!is_array($optGroups)) {
  66              throw new \InvalidArgumentException(hsc('Argument must be an associative array of label => [options]!'));
  67          }
  68          $this->optGroups = [];
  69          foreach ($optGroups as $label => $options) {
  70              $this->addOptGroup($label, $options);
  71          }
  72          return $this;
  73      }
  74  
  75      /**
  76       * Get or set the options of the Dropdown
  77       *
  78       * Options can be given as associative array (value => label) or as an
  79       * indexd array (label = value) or as an array of arrays. In the latter
  80       * case an element has to look as follows:
  81       * option-value => array (
  82       *                 'label' => option-label,
  83       *                 'attrs' => array (
  84       *                                    attr-key => attr-value, ...
  85       *                                  )
  86       *                 )
  87       *
  88       * @param null|array $options
  89       * @return $this|array
  90       */
  91      public function options($options = null)
  92      {
  93          if ($options === null) {
  94              return $this->optGroups['']->options();
  95          }
  96          $this->optGroups[''] = new OptGroup(null, $options);
  97          return $this;
  98      }
  99  
 100      /**
 101       * Get or set the current value
 102       *
 103       * When setting a value that is not defined in the options, the value is ignored
 104       * and the first option's value is selected instead
 105       *
 106       * @param null|string|string[] $value The value to set
 107       * @return $this|string|string[]
 108       */
 109      public function val($value = null)
 110      {
 111          // getter
 112          if ($value === null) {
 113              if (isset($this->attributes['multiple'])) {
 114                  return $this->values;
 115              } else {
 116                  return $this->values[0];
 117              }
 118          }
 119  
 120          // setter
 121          $this->values = $this->setValuesInOptGroups((array) $value);
 122          if (!$this->values) {
 123              // unknown value set, select first option instead
 124              $this->values = $this->setValuesInOptGroups((array) $this->getFirstOptionKey());
 125          }
 126  
 127          return $this;
 128      }
 129  
 130      /**
 131       * Returns the first option's key
 132       *
 133       * @return string
 134       */
 135      protected function getFirstOptionKey()
 136      {
 137          $options = $this->options();
 138          if (!empty($options)) {
 139              $keys = array_keys($options);
 140              return (string)array_shift($keys);
 141          }
 142          foreach ($this->optGroups as $optGroup) {
 143              $options = $optGroup->options();
 144              if (!empty($options)) {
 145                  $keys = array_keys($options);
 146                  return (string)array_shift($keys);
 147              }
 148          }
 149  
 150          return ''; // should not happen
 151      }
 152  
 153      /**
 154       * Set the value in the OptGroups, including the optgroup for the options without optgroup.
 155       *
 156       * @param string[] $values The values to be set
 157       * @return string[] The values actually set
 158       */
 159      protected function setValuesInOptGroups($values)
 160      {
 161          $valueset = [];
 162  
 163          /** @var OptGroup $optGroup */
 164          foreach ($this->optGroups as $optGroup) {
 165              $found = $optGroup->storeValues($values);
 166              $values = array_diff($values, $found);
 167              $valueset = array_merge($valueset, $found);
 168          }
 169  
 170          return $valueset;
 171      }
 172  
 173      /**
 174       * Create the HTML for the select it self
 175       *
 176       * @return string
 177       */
 178      protected function mainElementHTML()
 179      {
 180          $attr = $this->attrs();
 181          if (isset($attr['multiple'])) {
 182              // use array notation when multiple values are allowed
 183              $attr['name'] .= '[]';
 184          } elseif ($this->useInput) {
 185              // prefilling is only supported for non-multi fields
 186              $this->prefillInput();
 187          }
 188  
 189          $html = '<select ' . buildAttributes($attr) . '>';
 190          $html = array_reduce(
 191              $this->optGroups,
 192              static fn($html, OptGroup $optGroup) => $html . $optGroup->toHTML(),
 193              $html
 194          );
 195          $html .= '</select>';
 196  
 197          return $html;
 198      }
 199  }