[ 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 note that this does not support multiple selected options!
   9   *
  10   * @package dokuwiki\Form
  11   */
  12  class DropdownElement extends InputElement
  13  {
  14      /** @var array OptGroup[] */
  15      protected $optGroups = array();
  16  
  17      /**
  18       * @param string $name The name of this form element
  19       * @param array  $options The available options
  20       * @param string $label The label text for this element (will be autoescaped)
  21       */
  22      public function __construct($name, $options, $label = '')
  23      {
  24          parent::__construct('dropdown', $name, $label);
  25          $this->rmattr('type');
  26          $this->optGroups[''] = new OptGroup(null, $options);
  27          $this->val('');
  28      }
  29  
  30      /**
  31       * Add an `<optgroup>` and respective options
  32       *
  33       * @param string $label
  34       * @param array  $options
  35       * @return OptGroup a reference to the added optgroup
  36       * @throws \Exception
  37       */
  38      public function addOptGroup($label, $options)
  39      {
  40          if (empty($label)) {
  41              throw new \InvalidArgumentException(hsc('<optgroup> must have a label!'));
  42          }
  43          $this->optGroups[$label] = new OptGroup($label, $options);
  44          return end($this->optGroups);
  45      }
  46  
  47      /**
  48       * Set or get the optgroups of an Dropdown-Element.
  49       *
  50       * optgroups have to be given as associative array
  51       *   * the key being the label of the group
  52       *   * the value being an array of options as defined in @see OptGroup::options()
  53       *
  54       * @param null|array $optGroups
  55       * @return OptGroup[]|DropdownElement
  56       */
  57      public function optGroups($optGroups = null)
  58      {
  59          if ($optGroups === null) {
  60              return $this->optGroups;
  61          }
  62          if (!is_array($optGroups)) {
  63              throw new \InvalidArgumentException(hsc('Argument must be an associative array of label => [options]!'));
  64          }
  65          $this->optGroups = array();
  66          foreach ($optGroups as $label => $options) {
  67              $this->addOptGroup($label, $options);
  68          }
  69          return $this;
  70      }
  71  
  72      /**
  73       * Get or set the options of the Dropdown
  74       *
  75       * Options can be given as associative array (value => label) or as an
  76       * indexd array (label = value) or as an array of arrays. In the latter
  77       * case an element has to look as follows:
  78       * option-value => array (
  79       *                 'label' => option-label,
  80       *                 'attrs' => array (
  81       *                                    attr-key => attr-value, ...
  82       *                                  )
  83       *                 )
  84       *
  85       * @param null|array $options
  86       * @return $this|array
  87       */
  88      public function options($options = null)
  89      {
  90          if ($options === null) {
  91              return $this->optGroups['']->options();
  92          }
  93          $this->optGroups[''] = new OptGroup(null, $options);
  94          return $this;
  95      }
  96  
  97      /**
  98       * Gets or sets an attribute
  99       *
 100       * When no $value is given, the current content of the attribute is returned.
 101       * An empty string is returned for unset attributes.
 102       *
 103       * When a $value is given, the content is set to that value and the Element
 104       * itself is returned for easy chaining
 105       *
 106       * @param string $name Name of the attribute to access
 107       * @param null|string $value New value to set
 108       * @return string|$this
 109       */
 110      public function attr($name, $value = null)
 111      {
 112          if (strtolower($name) == 'multiple') {
 113              throw new \InvalidArgumentException(
 114                  'Sorry, the dropdown element does not support the "multiple" attribute'
 115              );
 116          }
 117          return parent::attr($name, $value);
 118      }
 119  
 120      /**
 121       * Get or set the current value
 122       *
 123       * When setting a value that is not defined in the options, the value is ignored
 124       * and the first option's value is selected instead
 125       *
 126       * @param null|string $value The value to set
 127       * @return $this|string
 128       */
 129      public function val($value = null)
 130      {
 131          if ($value === null) return $this->value;
 132  
 133          $value_exists = $this->setValueInOptGroups($value);
 134  
 135          if ($value_exists) {
 136              $this->value = $value;
 137          } else {
 138              // unknown value set, select first option instead
 139              $this->value = $this->getFirstOption();
 140              $this->setValueInOptGroups($this->value);
 141          }
 142  
 143          return $this;
 144      }
 145  
 146      /**
 147       * Returns the first options as it will be rendered in HTML
 148       *
 149       * @return string
 150       */
 151      protected function getFirstOption()
 152      {
 153          $options = $this->options();
 154          if (!empty($options)) {
 155              $keys = array_keys($options);
 156              return (string) array_shift($keys);
 157          }
 158          foreach ($this->optGroups as $optGroup) {
 159              $options = $optGroup->options();
 160              if (!empty($options)) {
 161                  $keys = array_keys($options);
 162                  return (string) array_shift($keys);
 163              }
 164          }
 165      }
 166  
 167      /**
 168       * Set the value in the OptGroups, including the optgroup for the options without optgroup.
 169       *
 170       * @param string $value
 171       * @return bool
 172       */
 173      protected function setValueInOptGroups($value)
 174      {
 175          $value_exists = false;
 176          /** @var OptGroup $optGroup */
 177          foreach ($this->optGroups as $optGroup) {
 178              $value_exists = $optGroup->storeValue($value) || $value_exists;
 179              if ($value_exists) {
 180                  $value = null;
 181              }
 182          }
 183          return $value_exists;
 184      }
 185  
 186      /**
 187       * Create the HTML for the select it self
 188       *
 189       * @return string
 190       */
 191      protected function mainElementHTML()
 192      {
 193          if ($this->useInput) $this->prefillInput();
 194  
 195          $html = '<select ' . buildAttributes($this->attrs()) . '>';
 196          $html = array_reduce(
 197              $this->optGroups,
 198              function ($html, OptGroup $optGroup) {
 199                  return $html . $optGroup->toHTML();
 200              },
 201              $html
 202          );
 203          $html .= '</select>';
 204  
 205          return $html;
 206      }
 207  
 208  }