From 52bcd2ac2640cf969f7dfbcfd4aebd9c85ad9852 Mon Sep 17 00:00:00 2001 From: Alexander Ebert Date: Fri, 16 Jun 2017 14:17:10 +0200 Subject: [PATCH] Added abstract implementation for custom options See #2308 --- .../form/AbstractCustomOptionForm.class.php | 258 ++++++++++++++++++ .../data/custom/option/CustomOption.class.php | 129 +++++++++ .../option/CustomOptionAction.class.php | 42 +++ .../option/CustomOptionEditor.class.php | 23 ++ .../custom/option/CustomOptionList.class.php | 38 +++ 5 files changed, 490 insertions(+) create mode 100644 wcfsetup/install/files/lib/acp/form/AbstractCustomOptionForm.class.php create mode 100644 wcfsetup/install/files/lib/data/custom/option/CustomOption.class.php create mode 100644 wcfsetup/install/files/lib/data/custom/option/CustomOptionAction.class.php create mode 100644 wcfsetup/install/files/lib/data/custom/option/CustomOptionEditor.class.php create mode 100644 wcfsetup/install/files/lib/data/custom/option/CustomOptionList.class.php diff --git a/wcfsetup/install/files/lib/acp/form/AbstractCustomOptionForm.class.php b/wcfsetup/install/files/lib/acp/form/AbstractCustomOptionForm.class.php new file mode 100644 index 0000000000..aa6455739f --- /dev/null +++ b/wcfsetup/install/files/lib/acp/form/AbstractCustomOptionForm.class.php @@ -0,0 +1,258 @@ + + * @package WoltLabSuite\Core\Acp\Form + * @since 3.1 + */ +abstract class AbstractCustomOptionForm extends AbstractAcpForm { + /** + * option name + * @var string + */ + public $optionTitle = ''; + + /** + * option description + * @var string + */ + public $optionDescription = ''; + + /** + * option type + * @var string + */ + public $optionType = 'text'; + + /** + * option default value + * @var string + */ + public $defaultValue = ''; + + /** + * validation pattern + * @var string + */ + public $validationPattern = ''; + + /** + * select options + * @var string + */ + public $selectOptions = ''; + + /** + * field is required + * @var boolean + */ + public $required = 0; + + /** + * show order + * @var integer + */ + public $showOrder = 0; + + /** + * action class name + * @var string + */ + public $actionClass = ''; + + /** + * base class name + * @var string + */ + public $baseClass = ''; + + /** + * editor class name + * @var string + */ + public $editorClass = ''; + + /** + * object instance + * @var Option + */ + public $object; + + /** + * object id + * @var integer + */ + public $objectID; + + /** + * available option types + * @var string[] + */ + public static $availableOptionTypes = [ + 'boolean', + 'checkboxes', + 'date', + 'integer', + 'float', + 'multiSelect', + 'radioButton', + 'select', + 'text', + 'textarea', + 'URL' + ]; + + /** + * list of option type that require select options + * @var string[] + */ + public static $optionTypesUsingSelectOptions = [ + 'checkboxes', + 'multiSelect', + 'radioButton', + 'select' + ]; + + /** + * @inheritDoc + */ + public function readParameters() { + parent::readParameters(); + + if (empty($this->action)) { + throw new \RuntimeException("The 'action' property must equal 'add' or 'edit'."); + } + + if ($this->action === 'edit') { + if (isset($_REQUEST['id'])) $this->objectID = intval($_REQUEST['id']); + $this->object = new $this->baseClass($this->objectID); + if (!$this->object->getObjectID()) { + throw new IllegalLinkException(); + } + } + + $this->registerI18nValue(new I18nValue('optionTitle')); + + $optionDescription = new I18nValue('optionDescription'); + $optionDescription->setFlags(I18nValue::ALLOW_EMPTY); + $this->registerI18nValue($optionDescription); + } + + /** + * @inheritDoc + */ + public function readFormParameters() { + parent::readFormParameters(); + + if (isset($_POST['optionType'])) $this->optionType = $_POST['optionType']; + if (isset($_POST['defaultValue'])) $this->defaultValue = $_POST['defaultValue']; + if (isset($_POST['validationPattern'])) $this->validationPattern = $_POST['validationPattern']; + if (isset($_POST['selectOptions'])) $this->selectOptions = $_POST['selectOptions']; + if (isset($_POST['required'])) $this->required = intval($_POST['required']); + if (isset($_POST['showOrder'])) $this->showOrder = intval($_POST['showOrder']); + + if ($this->optionType == 'boolean' || $this->optionType == 'integer') { + $this->defaultValue = intval($this->defaultValue); + } + if ($this->optionType == 'float') { + $this->defaultValue = floatval($this->defaultValue); + } + } + + /** + * @inheritDoc + */ + public function validate() { + parent::validate(); + + // option type + if (!in_array($this->optionType, self::$availableOptionTypes)) { + throw new UserInputException('optionType'); + } + + // select options + if (in_array($this->optionType, self::$optionTypesUsingSelectOptions) && empty($this->selectOptions)) { + throw new UserInputException('selectOptions'); + } + } + + /** + * Returns the list of database values including additional fields. + * + * @return array + */ + protected function getDatabaseValues() { + return array_merge($this->additionalFields, [ + 'optionTitle' => $this->optionTitle, + 'optionDescription' => $this->optionDescription, + 'optionType' => $this->optionType, + 'defaultValue' => $this->defaultValue, + 'showOrder' => $this->showOrder, + 'validationPattern' => $this->validationPattern, + 'selectOptions' => $this->selectOptions, + 'required' => $this->required + ]); + } + + /** + * @inheritDoc + */ + public function save() { + parent::save(); + + if ($this->action === 'add') { + $this->objectAction = new $this->actionClass([], 'create', ['data' => $this->getDatabaseValues()]); + + $this->saveI18n($this->objectAction->executeAction()['returnValues'], $this->editorClass); + + $this->reset(); + } + else { + $this->saved(); + + // show success message + WCF::getTPL()->assign('success', true); + } + } + + /** + * @inheritDoc + */ + public function reset() { + parent::reset(); + + // reset values + $this->optionTitle = $this->optionDescription = $this->optionType = $this->defaultValue = $this->validationPattern = $this->selectOptions = ''; + $this->optionType = 'text'; + $this->required = $this->showOrder = 0; + } + + /** + * @inheritDoc + */ + public function assignVariables() { + parent::assignVariables(); + + WCF::getTPL()->assign([ + 'defaultValue' => $this->defaultValue, + 'validationPattern' => $this->validationPattern, + 'optionType' => $this->optionType, + 'selectOptions' => $this->selectOptions, + 'required' => $this->required, + 'showOrder' => $this->showOrder, + 'action' => $this->action, + 'availableOptionTypes' => self::$availableOptionTypes, + 'optionTypesUsingSelectOptions' => self::$optionTypesUsingSelectOptions + ]); + } +} diff --git a/wcfsetup/install/files/lib/data/custom/option/CustomOption.class.php b/wcfsetup/install/files/lib/data/custom/option/CustomOption.class.php new file mode 100644 index 0000000000..246c53ee01 --- /dev/null +++ b/wcfsetup/install/files/lib/data/custom/option/CustomOption.class.php @@ -0,0 +1,129 @@ + + * @package WoltLabSuite\Core\Data\Custom\Option + * @since 3.1 + * + * @property-read integer $optionID unique id of the option + * @property-read string $optionTitle title of the option or name of language item which contains the title + * @property-read string $optionDescription description of the option or name of language item which contains the description + * @property-read string $optionType type of the option which determines its input and output + * @property-read string $defaultValue default value of the option + * @property-read string $validationPattern regular expression used to validate the value of the option + * @property-read string $selectOptions possible values of the option separated by newlines + * @property-read integer $required is `1` if the option has to be filled out, otherwise `0` + * @property-read integer $showOrder position of the option relation tp the other options + * @property-read integer $isDisabled is `1` if the option is disabled, otherwise `0` + */ +abstract class CustomOption extends Option { + /** + * option value + * @var string + */ + protected $optionValue = ''; + + /** + * Returns true if the option is visible + * + * @return boolean + */ + public function isVisible() { + return !$this->isDisabled; + } + + /** + * @inheritDoc + */ + public static function getDatabaseTableAlias() { + throw new NotImplementedException(); + } + + /** + * Returns the value of this option. + * + * @return string + */ + public function getOptionValue() { + return $this->optionValue; + } + + /** + * Sets the value of this option. + * + * @param string $value + */ + public function setOptionValue($value) { + $this->optionValue = $value; + } + + /** + * Returns the formatted value of this option. + * + * @return string + */ + public function getFormattedOptionValue() { + switch ($this->optionType) { + case 'boolean': + return WCF::getLanguage()->get('wcf.acp.option.optionType.boolean.'.($this->optionValue ? 'yes' : 'no')); + + case 'date': + $year = $month = $day = 0; + $optionValue = explode('-', $this->optionValue); + if (isset($optionValue[0])) $year = intval($optionValue[0]); + if (isset($optionValue[1])) $month = intval($optionValue[1]); + if (isset($optionValue[2])) $day = intval($optionValue[2]); + return DateUtil::format(DateUtil::getDateTimeByTimestamp(gmmktime(12, 1, 1, $month, $day, $year)), DateUtil::DATE_FORMAT); + + case 'float': + return StringUtil::formatDouble(intval($this->optionValue)); + + case 'integer': + return StringUtil::formatInteger(intval($this->optionValue)); + + case 'radioButton': + case 'select': + $selectOptions = OptionUtil::parseSelectOptions($this->selectOptions); + if (isset($selectOptions[$this->optionValue])) return WCF::getLanguage()->get($selectOptions[$this->optionValue]); + return ''; + + case 'multiSelect': + case 'checkboxes': + $selectOptions = OptionUtil::parseSelectOptions($this->selectOptions); + $values = explode("\n", $this->optionValue); + $result = ''; + foreach ($values as $value) { + if (isset($selectOptions[$value])) { + if (!empty($result)) $result .= "
\n"; + $result .= WCF::getLanguage()->get($selectOptions[$value]); + } + } + return $result; + + case 'textarea': + return SimpleMessageParser::getInstance()->parse($this->optionValue); + + case 'message': + return MessageParser::getInstance()->parse($this->optionValue); + + case 'URL': + return StringUtil::getAnchorTag($this->optionValue); + + default: + return StringUtil::encodeHTML($this->optionValue); + } + } +} diff --git a/wcfsetup/install/files/lib/data/custom/option/CustomOptionAction.class.php b/wcfsetup/install/files/lib/data/custom/option/CustomOptionAction.class.php new file mode 100644 index 0000000000..9c170e5822 --- /dev/null +++ b/wcfsetup/install/files/lib/data/custom/option/CustomOptionAction.class.php @@ -0,0 +1,42 @@ + + * @package WoltLabSuite\Core\Data\Custom\Option + * @since 3.1 + * + * @method CustomOption create() + * @method CustomOptionEditor[] getObjects() + * @method CustomOptionEditor getSingleObject() + */ +abstract class CustomOptionAction extends AbstractDatabaseObjectAction implements IToggleAction { + /** + * @inheritDoc + */ + protected $className = CustomOptionEditor::class; + + /** + * @inheritDoc + */ + public function validateToggle() { + $this->validateUpdate(); + } + + /** + * @inheritDoc + */ + public function toggle() { + foreach ($this->getObjects() as $optionEditor) { + $optionEditor->update([ + 'isDisabled' => 1 - $optionEditor->isDisabled + ]); + } + } +} diff --git a/wcfsetup/install/files/lib/data/custom/option/CustomOptionEditor.class.php b/wcfsetup/install/files/lib/data/custom/option/CustomOptionEditor.class.php new file mode 100644 index 0000000000..a7270886da --- /dev/null +++ b/wcfsetup/install/files/lib/data/custom/option/CustomOptionEditor.class.php @@ -0,0 +1,23 @@ + + * @package WoltLabSuite\Core\Data\Custom\Option + * @since 3.1 + * + * @method static CustomOption create(array $parameters = []) + * @method CustomOption getDecoratedObject() + * @mixin CustomOption + */ +abstract class CustomOptionEditor extends DatabaseObjectEditor { + /** + * @inheritDoc + */ + protected static $baseClass = CustomOption::class; +} diff --git a/wcfsetup/install/files/lib/data/custom/option/CustomOptionList.class.php b/wcfsetup/install/files/lib/data/custom/option/CustomOptionList.class.php new file mode 100644 index 0000000000..8c5bb394ec --- /dev/null +++ b/wcfsetup/install/files/lib/data/custom/option/CustomOptionList.class.php @@ -0,0 +1,38 @@ + + * @package WoltLabSuite\Core\Data\Custom\Option + * @since 3.1 + * + * @method CustomOption current() + * @method CustomOption[] getObjects() + * @method CustomOption|null search($objectID) + * @property CustomOption[] $objects + */ +abstract class CustomOptionList extends DatabaseObjectList { + /** + * @inheritDoc + */ + public $className = CustomOption::class; + + /** + * @inheritDoc + */ + public $sqlOrderBy = 'showOrder'; + + /** + * @inheritDoc + */ + public function __construct() { + parent::__construct(); + + $this->sqlSelects = "CONCAT('customOption', CAST({$this->getDatabaseTableAlias()}.optionID AS CHAR)) AS optionName"; + } +} -- 2.20.1