Add single selection form field
authorMatthias Schmidt <gravatronics@live.com>
Thu, 11 Jan 2018 17:27:32 +0000 (18:27 +0100)
committerMatthias Schmidt <gravatronics@live.com>
Thu, 11 Jan 2018 17:28:35 +0000 (18:28 +0100)
See #2509

wcfsetup/install/files/acp/templates/__singleSelectionFormField.tpl [new file with mode: 0644]
wcfsetup/install/files/lib/acp/form/DevtoolsFormBuilderTestForm.class.php
wcfsetup/install/files/lib/system/form/builder/field/ISelectionFormField.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/form/builder/field/SingleSelectionFormField.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/form/builder/field/TSelectionFormField.class.php [new file with mode: 0644]

diff --git a/wcfsetup/install/files/acp/templates/__singleSelectionFormField.tpl b/wcfsetup/install/files/acp/templates/__singleSelectionFormField.tpl
new file mode 100644 (file)
index 0000000..1a0a816
--- /dev/null
@@ -0,0 +1,12 @@
+<dl{if !$field->getClasses()|empty} class="{implode from=$field->getClasses() item='class'}{$class}{/implode}"{/if}{foreach from=$field->getAttributes() key='attributeName' item='attributeValue'} {$attributeName}="{$attributeValue}"{/foreach}>
+       <dt><label for="{@$field->getPrefixedId()}">{@$field->getLabel()}</label></dt>
+       <dd>
+               <select id="{@$field->getPrefixedId()}" name="{@$field->getPrefixedId()}">
+                       {htmlOptions options=$field->getOptions() selected=$field->getValue()}
+               </select>
+               
+               {include file='__formFieldDescription'}
+               
+               {include file='__formFieldErrors'}
+       </dd>
+</dl>
index ec5d5307dd3d40852d1ae485cbbab55ae46db0af..6bf20101aaa502ca3f3e24c65a7cdcaeb9108772 100644 (file)
@@ -6,6 +6,7 @@ use wcf\system\form\builder\container\FormContainer;
 use wcf\system\form\builder\container\TabFormContainer;
 use wcf\system\form\builder\container\TabMenuFormContainer;
 use wcf\system\form\builder\field\data\CustomFormFieldDataProcessor;
+use wcf\system\form\builder\field\SingleSelectionFormField;
 use wcf\system\form\builder\field\validation\FormFieldValidationError;
 use wcf\system\form\builder\field\validation\FormFieldValidator;
 use wcf\system\form\builder\field\BooleanFormField;
@@ -92,7 +93,32 @@ class DevtoolsFormBuilderTestForm extends AbstractForm {
                                                                        'You have to select Yes for this field!'
                                                                ));
                                                        }
-                                               }))
+                                               })),
+                                       SingleSelectionFormField::create('year')
+                                               ->label('Year')
+                                               ->options(function() {
+                                                       return [
+                                                               '(no selection)',
+                                                               2016 => 2016,
+                                                               2017 => 2017,
+                                                               2018 => 2018,
+                                                               2019 => 2019
+                                                       ];
+                                               }),
+                                       SingleSelectionFormField::create('month')
+                                               ->label('Month')
+                                               ->options([
+                                                       'Spring' => [
+                                                               3 => 'March',
+                                                               4 => 'April',
+                                                               5 => 'May'
+                                                       ],
+                                                       'Summer' => [
+                                                               6 => 'June',
+                                                               7 => 'July',
+                                                               8 => 'August'
+                                                       ]
+                                               ])
                                ]),
                        TabMenuFormContainer::create('tabMenu')
                                ->appendChildren([
diff --git a/wcfsetup/install/files/lib/system/form/builder/field/ISelectionFormField.class.php b/wcfsetup/install/files/lib/system/form/builder/field/ISelectionFormField.class.php
new file mode 100644 (file)
index 0000000..05d9817
--- /dev/null
@@ -0,0 +1,33 @@
+<?php
+namespace wcf\system\form\builder\field;
+
+/**
+ * Represents a form field that consists of a predefined set of possible values.
+ * 
+ * @author     Matthias Schmidt
+ * @copyright  2001-2018 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    WoltLabSuite\Core\System\Form\Builder\Field
+ * @since      3.2
+ */
+interface ISelectionFormField {
+       /**
+        * Returns the possible options of this field.
+        * 
+        * @return      array
+        * 
+        * @throws      \BadMethodCallException         if no options have been set
+        */
+       public function getOptions();
+       
+       /**
+        * Sets the possible options of this field and returns this field.
+        * 
+        * @param       array|callable          $options        selectable options or callable returning the options
+        * @return      static                                  this field
+        * 
+        * @throws      \InvalidArgumentException               if given options are no array or callable or otherwise invalid
+        * @throws      \UnexpectedValueException               if callable does not return an array
+        */
+       public function options($options);
+}
diff --git a/wcfsetup/install/files/lib/system/form/builder/field/SingleSelectionFormField.class.php b/wcfsetup/install/files/lib/system/form/builder/field/SingleSelectionFormField.class.php
new file mode 100644 (file)
index 0000000..9652a01
--- /dev/null
@@ -0,0 +1,20 @@
+<?php
+namespace wcf\system\form\builder\field;
+
+/**
+ * Implementation of a form field for selecting a single value.
+ * 
+ * @author     Matthias Schmidt
+ * @copyright  2001-2018 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    WoltLabSuite\Core\System\Form\Builder\Field
+ * @since      3.2
+ */
+class SingleSelectionFormField extends AbstractFormField {
+       use TSelectionFormField;
+       
+       /**
+        * @inheritDoc
+        */
+       protected $templateName = '__singleSelectionFormField';
+}
diff --git a/wcfsetup/install/files/lib/system/form/builder/field/TSelectionFormField.class.php b/wcfsetup/install/files/lib/system/form/builder/field/TSelectionFormField.class.php
new file mode 100644 (file)
index 0000000..8538c77
--- /dev/null
@@ -0,0 +1,106 @@
+<?php
+namespace wcf\system\form\builder\field;
+use wcf\system\form\builder\field\validation\FormFieldValidationError;
+
+/**
+ * Provides default implementations of `ISelectionFormField` methods.
+ * 
+ * @author     Matthias Schmidt
+ * @copyright  2001-2018 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    WoltLabSuite\Core\System\Form\Builder\Field
+ * @since      3.2
+ */
+trait TSelectionFormField {
+       /**
+        * possible options to select
+        * @var null|array
+        */
+       protected $__options;
+       
+       /**
+        * possible values of the selection
+        * @var array 
+        */
+       protected $possibleValues = [];
+       
+       /**
+        * Returns the possible options of this field.
+        * 
+        * @return      array
+        * 
+        * @throws      \BadMethodCallException         if no options have been set
+        */
+       public function getOptions() {
+               return $this->__options;
+       }
+       
+       /**
+        * Sets the possible options of this selection and returns this field.
+        * 
+        * @param       array|callable          $options        selectable options or callable returning the options
+        * @return      static                                  this field
+        * 
+        * @throws      \InvalidArgumentException               if given options are no array or callable or otherwise invalid
+        * @throws      \UnexpectedValueException               if callable does not return an array
+        */
+       public function options($options) {
+               if (!is_array($options) && !is_callable($options)) {
+                       throw new \InvalidArgumentException("Given options are neither an array nor a callable, " . gettype($options) . " given.");
+               }
+               
+               if (is_callable($options)) {
+                       $options = $options();
+                       
+                       if (!is_array($options)) {
+                               throw new \UnexpectedValueException("The options callable is expected to return an array, " . gettype($options) . " returned.");
+                       }
+               }
+               
+               // validate options and read possible values
+               $validateOptions = function($array) use (&$validateOptions) {
+                       foreach ($array as $key => $value) {
+                               if (is_array($value)) {
+                                       $validateOptions($value);
+                               }
+                               else {
+                                       if (!is_string($value) && !is_numeric($value)) {
+                                               throw new \InvalidArgumentException("Options contain invalid label of type " . gettype($value) . ".");
+                                       }
+                                       
+                                       if (in_array($key, $this->possibleValues)) {
+                                               throw new \InvalidArgumentException("Options values must be unique, but '" . $key . "' appears at least twice as value.");
+                                       }
+                                       
+                                       $this->possibleValues[] = $key;
+                               }
+                       }
+               };
+               
+               $validateOptions($options);
+               
+               $this->__options = $options;
+               
+               return $this;
+       }
+       
+       /**
+        * @inheritDoc
+        */
+       public function readValue() {
+               if (isset($_POST[$this->getPrefixedId()]) && is_string($_POST[$this->getPrefixedId()])) {
+                       $this->__value = $_POST[$this->getPrefixedId()];
+               }
+       }
+       
+       /**
+        * @inheritDoc
+        */
+       public function validate() {
+               if (!in_array($this->getValue(), $this->possibleValues)) {
+                       $this->addValidationError(new FormFieldValidationError('invalidValue', 'wcf.global.form.selection.error.invalidValue'));
+               }
+               
+               parent::validate();
+       }
+}