Add interface and trait for form fields supporting multiple values
authorMatthias Schmidt <gravatronics@live.com>
Mon, 26 Feb 2018 19:09:27 +0000 (20:09 +0100)
committerMatthias Schmidt <gravatronics@live.com>
Mon, 26 Feb 2018 19:09:27 +0000 (20:09 +0100)
See #2509

wcfsetup/install/files/lib/system/form/builder/field/IMultipleFormField.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/form/builder/field/TMultipleFormField.class.php [new file with mode: 0644]

diff --git a/wcfsetup/install/files/lib/system/form/builder/field/IMultipleFormField.class.php b/wcfsetup/install/files/lib/system/form/builder/field/IMultipleFormField.class.php
new file mode 100644 (file)
index 0000000..f307348
--- /dev/null
@@ -0,0 +1,77 @@
+<?php
+namespace wcf\system\form\builder\field;
+
+/**
+ * Represents a form field that support selecting or setting multiple 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 IMultipleFormField {
+       /**
+        * value to indicate that there is no maximum number of values to be selected
+        * or set
+        */
+       const NO_MAXIMUM_MULTIPLES = -1;
+       
+       /**
+        * Returns `true` if multiple values can be selected or set and returns `false`
+        * otherwise.
+        * 
+        * Per default, fields do not allow multiple values.
+        * 
+        * @return      bool
+        */
+       public function allowsMultiple(): bool;
+       
+       /**
+        * Returns the maximum number of values that can be selected or set.
+        * If there is no maximum number, `IMultipleFormField::NO_MAXIMUM_MULTIPLES`
+        * is returned.
+        * 
+        * @return      int     maximum number of values
+        */
+       public function getMaximumMultiples(): int;
+       
+       /**
+        * Returns the minimum number of values that can be selected or set.
+        * 
+        * Per default, there is no minimum number.
+        *
+        * @return      int     minimum number of values
+        */
+       public function getMinimumMultiples(): int;
+       
+       /**
+        * Sets the maximum number of values that can be selected or set and returns
+        * this field. To unset the maximum number, pass `IMultipleFormField::NO_MAXIMUM_MULTIPLES`.
+        * 
+        * @param       int             $maximum        maximum number of values
+        * @return      static                          this field
+        * 
+        * @throws      \InvalidArgumentException       if the given maximum number of values is invalid
+        */
+       public function maximumMultiples(int $maximum): IMultipleFormField;
+       
+       /**
+        * Sets the minimum number of values that can be selected or set and returns
+        * this field.
+        *
+        * @param       int             $maximum        maximum number of values
+        * @return      static                          this field
+        * 
+        * @throws      \InvalidArgumentException       if the given minimum number of values is invalid
+        */
+       public function minimumMultiples(int $minimum): IMultipleFormField;
+       
+       /**
+        * Sets whether multiple values can be selected or set and returns this field.
+        * 
+        * @param       bool            $multiple       determines if multiple values can be selected/set
+        * @return      static                          this field
+        */
+       public function multiple(bool $multiple = true): IMultipleFormField;
+}
diff --git a/wcfsetup/install/files/lib/system/form/builder/field/TMultipleFormField.class.php b/wcfsetup/install/files/lib/system/form/builder/field/TMultipleFormField.class.php
new file mode 100644 (file)
index 0000000..ef22d5e
--- /dev/null
@@ -0,0 +1,187 @@
+<?php
+namespace wcf\system\form\builder\field;
+use wcf\system\form\builder\field\data\CustomFormFieldDataProcessor;
+use wcf\system\form\builder\IFormDocument;
+use wcf\system\form\builder\IFormNode;
+
+/**
+ * Provides default implementations of `IMultipleFormField` 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 TMultipleFormField {
+       /**
+        * maximum number of values that can be selected or set
+        * @var int
+        */
+       protected $__maximumMultiples = IMultipleFormField::NO_MAXIMUM_MULTIPLES;
+       
+       /**
+        * minimum number of values that can be selected or set
+        * @var int
+        */
+       protected $__minimumMultiples = 0;
+       
+       /**
+        * `true` if this field allows multiple values to be selected or set and `false` otherwise
+        * @var bool
+        */
+       protected $__multiple = false;
+       
+       /**
+        * Returns `true` if multiple values can be selected or set and returns `false`
+        * otherwise.
+        *
+        * Per default, fields do not allow multiple values.
+        *
+        * @return      bool
+        */
+       public function allowsMultiple(): bool {
+               return $this->__multiple;
+       }
+       
+       /**
+        * Returns the maximum number of values that can be selected or set.
+        * If there is no maximum number, `IMultipleFormField::NO_MAXIMUM_MULTIPLES`
+        * is returned.
+        *
+        * @return      int     maximum number of values
+        */
+       public function getMaximumMultiples(): int {
+               return $this->__maximumMultiples;
+       }
+       
+       /**
+        * Returns the minimum number of values that can be selected or set.
+        *
+        * Per default, there is no minimum number.
+        *
+        * @return      int     minimum number of values
+        */
+       public function getMinimumMultiples(): int {
+               return $this->__minimumMultiples;
+       }
+       
+       /**
+        * Returns `true` if this field provides a value that can simply be stored
+        * in a column of the database object's database table and returns `false`
+        * otherwise.
+        * 
+        * Note: If `false` is returned, this field should probabily add its own
+        * `IFormFieldDataProcessor` object to the form document's data processor.
+        * A suitable place to add the processor is the `populate()` method.
+        * 
+        * @return      bool
+        */
+       public function hasSaveValue(): bool {
+               return !$this->allowsMultiple();
+       }
+       
+       /**
+        * Sets the maximum number of values that can be selected or set and returns
+        * this field. To unset the maximum number, pass `IMultipleFormField::NO_MAXIMUM_MULTIPLES`.
+        *
+        * @param       int             $maximum        maximum number of values
+        * @return      static                          this field
+        * 
+        * @throws      \InvalidArgumentException       if the given maximum number of values is invalid
+        */
+       public function maximumMultiples(int $maximum): IMultipleFormField {
+               if ($maximum !== IMultipleFormField::NO_MAXIMUM_MULTIPLES) {
+                       if ($maximum <= 0) {
+                               throw new \InvalidArgumentException("The maximum number of values has to be positive, '{$minimum}' given.");
+                       }
+                       
+                       if ($this->getMinimumMultiples() !== 0 && $maximum < $this->getMinimumMultiples()) {
+                               throw new \InvalidArgumentException("The given maximum number of values '{$maximum}' is less than the set minimum number of values '{$this->getMinimumMultiples()}'.");
+                       }
+               }
+               
+               $this->__maximumMultiples = $maximum;
+               
+               return $this;
+       }
+       
+       /**
+        * Sets the minimum number of values that can be selected or set and returns
+        * this field.
+        * 
+        * @param       int             $maximum        maximum number of values
+        * @return      static                          this field
+        * 
+        * @throws      \InvalidArgumentException       if the given minimum number of values is invalid
+        */
+       public function minimumMultiples(int $minimum): IMultipleFormField {
+               if ($minimum < 0) {
+                       throw new \InvalidArgumentException("The minimum number of values has to be non-negative, '{$minimum}' given.");
+               }
+               
+               if ($this->getMaximumMultiples() !== IMultipleFormField::NO_MAXIMUM_MULTIPLES && $minimum > $this->getMaximumMultiples()) {
+                       throw new \InvalidArgumentException("The given minimum number of values '{$minimum}' is greater than the set maximum number of values '{$this->getMaximumMultiples()}'.");
+               }
+               
+               $this->__minimumMultiples = $minimum;
+               
+               return $this;
+       }
+       
+       /**
+        * Sets whether multiple values can be selected or set and returns this field.
+        *
+        * @param       bool            $multiple       determines if multiple values can be selected/set
+        * @return      static          this field
+        */
+       public function multiple(bool $multiple = true): IMultipleFormField {
+               $this->__multiple = $multiple;
+               
+               return $this;
+       }
+       
+       /**
+        * Is called once after all nodes have been added to the document this node belongs to.
+        * 
+        * This method enables this node to perform actions that require the whole document having
+        * finished constructing itself and every parent-child relationship being established.
+        * 
+        * @return      static                          this node
+        * 
+        * @throws      \BadMethodCallException         if this node has already been populated
+        */
+       public function populate(): IFormNode {
+               parent::populate();
+               
+               if ($this->allowsMultiple()) {
+                       $this->getDocument()->getDataHandler()->add(new CustomFormFieldDataProcessor('multiple', function(IFormDocument $document, array $parameters) {
+                               if (!empty($this->getValue())) {
+                                       $parameters[$this->getId()] = $this->getValue();
+                               }
+                               
+                               return $parameters;
+                       }));
+               }
+               
+               return $this;
+       }
+       
+       /**
+        * Sets the value of this field and returns this field.
+        * 
+        * @param       mixed           $value          new field value
+        * @return      static                          this field
+        * 
+        * @throws      \InvalidArgumentException       if the given value is of an invalid type or otherwise is invalid
+        */
+       public function value($value): IFormField {
+               // ensure array value for form fields that actually support multiple values;
+               // allows enabling support for multiple values for existing fields
+               if ($this->allowsMultiple() && !is_array($value)) {
+                       $value = [$value];
+               } 
+               
+               return parent::value($value);
+       }
+}