From 1891720728cfcbd1e0279cf022101ed73faef1ee Mon Sep 17 00:00:00 2001 From: Cyperghost Date: Thu, 14 Nov 2024 12:13:48 +0100 Subject: [PATCH] Use the FormBuilder to create/edit tags --- .../files/acp/templates/__tagFormSynonym.tpl | 6 + .../install/files/acp/templates/tagAdd.tpl | 83 +----- .../files/lib/acp/form/TagAddForm.class.php | 281 +++++++----------- .../files/lib/acp/form/TagEditForm.class.php | 134 ++------- .../files/lib/data/tag/TagAction.class.php | 63 +++- 5 files changed, 191 insertions(+), 376 deletions(-) create mode 100644 wcfsetup/install/files/acp/templates/__tagFormSynonym.tpl diff --git a/wcfsetup/install/files/acp/templates/__tagFormSynonym.tpl b/wcfsetup/install/files/acp/templates/__tagFormSynonym.tpl new file mode 100644 index 0000000000..e72e83228a --- /dev/null +++ b/wcfsetup/install/files/acp/templates/__tagFormSynonym.tpl @@ -0,0 +1,6 @@ +
+
+
+ {$synonym->name} +
+
diff --git a/wcfsetup/install/files/acp/templates/tagAdd.tpl b/wcfsetup/install/files/acp/templates/tagAdd.tpl index 86da527c48..c8686d132c 100644 --- a/wcfsetup/install/files/acp/templates/tagAdd.tpl +++ b/wcfsetup/install/files/acp/templates/tagAdd.tpl @@ -14,87 +14,6 @@ -{include file='shared_formNotice'} - -
-
- -
-
- - {if $errorField == 'name'} - - {if $errorType == 'empty'} - {lang}wcf.global.form.error.empty{/lang} - {elseif $errorType == 'duplicate'} - {lang}wcf.acp.tag.error.name.duplicate{/lang} - {/if} - - {/if} -
- - - {hascontent} - -
-
- - {if $errorField == 'languageID'} - - {lang}wcf.acp.tag.error.languageID.{$errorType}{/lang} - - {/if} -
- - {/hascontent} - - {if !$tagObj|isset || $tagObj->synonymFor === null} -
-
-
- -
-
- - - {elseif $tagObj|isset} -
-
-
- {$synonym->name} -
-
- {/if} - - {event name='dataFields'} -
- - {event name='sections'} - -
- - {csrfToken} -
-
+{unsafe:$form->getHtml()} {include file='footer'} diff --git a/wcfsetup/install/files/lib/acp/form/TagAddForm.class.php b/wcfsetup/install/files/lib/acp/form/TagAddForm.class.php index f86d3f7ccc..57c80f777a 100644 --- a/wcfsetup/install/files/lib/acp/form/TagAddForm.class.php +++ b/wcfsetup/install/files/lib/acp/form/TagAddForm.class.php @@ -2,25 +2,34 @@ namespace wcf\acp\form; +use wcf\data\IStorableObject; use wcf\data\tag\Tag; use wcf\data\tag\TagAction; -use wcf\data\tag\TagEditor; -use wcf\form\AbstractForm; -use wcf\system\exception\UserInputException; +use wcf\data\tag\TagList; +use wcf\form\AbstractFormBuilderForm; +use wcf\system\form\builder\container\FormContainer; +use wcf\system\form\builder\data\processor\CustomFormDataProcessor; +use wcf\system\form\builder\field\SingleSelectionFormField; +use wcf\system\form\builder\field\tag\TagFormField; +use wcf\system\form\builder\field\TextFormField; +use wcf\system\form\builder\field\validation\FormFieldValidationError; +use wcf\system\form\builder\field\validation\FormFieldValidator; +use wcf\system\form\builder\IFormDocument; +use wcf\system\form\builder\TemplateFormNode; use wcf\system\language\LanguageFactory; -use wcf\system\request\LinkHandler; use wcf\system\WCF; -use wcf\util\ArrayUtil; use wcf\util\StringUtil; /** * Shows the tag add form. * - * @author Tim Duesterhus - * @copyright 2001-2019 WoltLab GmbH - * @license GNU Lesser General Public License + * @author Olaf Braun, Tim Duesterhus + * @copyright 2001-2024 WoltLab GmbH + * @license GNU Lesser General Public License + * + * @property Tag $formObject */ -class TagAddForm extends AbstractForm +class TagAddForm extends AbstractFormBuilderForm { /** * @inheritDoc @@ -37,188 +46,102 @@ class TagAddForm extends AbstractForm */ public $neededModules = ['MODULE_TAGGING']; - /** - * list of available languages - * @var array - */ - public $availableLanguages = []; - - /** - * name value - * @var string - */ - public $name = ''; - - /** - * language value - * @var string - */ - public $languageID = 0; - - /** - * synonyms - * @var string[] - */ - public $synonyms = []; - /** * @inheritDoc */ - public function readParameters() - { - parent::readParameters(); - - $this->availableLanguages = LanguageFactory::getInstance()->getContentLanguages(); - } + public $objectActionClass = TagAction::class; /** * @inheritDoc */ - public function readFormParameters() - { - parent::readFormParameters(); - - if (isset($_POST['name'])) { - $this->name = \str_replace(',', '', StringUtil::trim($_POST['name'])); - } - if (isset($_POST['languageID'])) { - $this->languageID = \intval($_POST['languageID']); - } + public $objectEditLinkController = TagEditForm::class; - // actually these are synonyms - if (isset($_POST['tags']) && \is_array($_POST['tags'])) { - $this->synonyms = ArrayUtil::trim($_POST['tags']); - } - } - - /** - * @inheritDoc - */ - public function validate() + #[\Override] + protected function createForm() { - parent::validate(); - - if (empty($this->name)) { - throw new UserInputException('name'); - } - - // validate language - if (!isset($this->tagObj)) { - if (empty($this->availableLanguages)) { - // force default language id - $this->languageID = LanguageFactory::getInstance()->getDefaultLanguageID(); - } else { - if (!isset($this->availableLanguages[$this->languageID])) { - throw new UserInputException('languageID', 'notFound'); - } - } - } - - // check for duplicates - $tag = Tag::getTag($this->name, $this->languageID); - if ($tag !== null && (!isset($this->tagObj) || $tag->tagID != $this->tagObj->tagID)) { - throw new UserInputException('name', 'duplicate'); - } - - // validate synonyms - foreach ($this->synonyms as $key => $synonym) { - if (\mb_strtolower($synonym) == \mb_strtolower($this->name)) { - unset($this->synonyms[$key]); - } - } - } - - /** - * @inheritDoc - */ - public function readData() - { - parent::readData(); - - if (empty($_POST)) { - // pre-select default language id - if (!empty($this->availableLanguages)) { - $this->languageID = LanguageFactory::getInstance()->getDefaultLanguageID(); - if (!isset($this->availableLanguages[$this->languageID])) { - // language id is not within content languages, try user's language instead - $this->languageID = WCF::getUser()->languageID; - if (!isset($this->availableLanguages[$this->languageID])) { - // this installation is weird, just select nothing - $this->languageID = 0; - } - } - } - } - } - - /** - * @inheritDoc - */ - public function save() - { - parent::save(); - - // save tag - $this->objectAction = new TagAction([], 'create', [ - 'data' => \array_merge($this->additionalFields, [ - 'name' => $this->name, - 'languageID' => $this->languageID, - ]), - ]); - $this->objectAction->executeAction(); - $returnValues = $this->objectAction->getReturnValues(); - $editor = new TagEditor($returnValues['returnValues']); - - foreach ($this->synonyms as $synonym) { - if (empty($synonym)) { - continue; - } - - // find existing tag - $synonymObj = Tag::getTag($synonym, $this->languageID); - if ($synonymObj === null) { - $synonymAction = new TagAction([], 'create', [ - 'data' => [ - 'name' => $synonym, - 'languageID' => $this->languageID, - 'synonymFor' => $editor->tagID, - ], - ]); - $synonymAction->executeAction(); - } else { - $editor->addSynonym($synonymObj); - } - } - - $this->saved(); - - // reset values - $this->name = ''; - $this->synonyms = []; - - // show success message - WCF::getTPL()->assign([ - 'success' => true, - 'objectEditLink' => LinkHandler::getInstance()->getControllerLink( - TagEditForm::class, - ['id' => $returnValues['returnValues']->tagID] - ), + parent::createForm(); + + $this->form->appendChildren([ + FormContainer::create('general') + ->appendChildren([ + TextFormField::create('name') + ->label('wcf.global.name') + ->required() + ->maximumLength(TAGGING_MAX_TAG_LENGTH) + ->addValidator( + new FormFieldValidator('duplicateTagValidator', function (TextFormField $field) { + $languageIDFormField = $field->getDocument()->getNodeById('languageID'); + \assert($languageIDFormField instanceof SingleSelectionFormField); + $languageID = $languageIDFormField->getValue(); + + $tag = Tag::getTag($field->getValue(), $languageID); + if ($tag !== null && $tag->tagID !== $this->formObject?->tagID) { + $field->addValidationError( + new FormFieldValidationError( + 'duplicate', + 'wcf.acp.tag.error.name.duplicate' + ) + ); + } + }) + ), + SingleSelectionFormField::create('languageID') + ->label('wcf.acp.tag.languageID') + ->options(LanguageFactory::getInstance()->getContentLanguages()) + ->value(WCF::getUser()->languageID) + ->immutable($this->formAction !== 'create') + ->required(), + TagFormField::create('synonyms') + ->available($this->formObject?->synonymFor === null) + ->label('wcf.acp.tag.synonyms'), + TemplateFormNode::create('tagSynonymFor') + ->available($this->formObject?->synonymFor !== null) + ->variables([ + 'synonym' => new Tag($this->formObject?->synonymFor), + ]) + ->templateName('__tagFormSynonym') + ]) ]); } - /** - * @inheritDoc - */ - public function assignVariables() + #[\Override] + protected function finalizeForm() { - parent::assignVariables(); - - WCF::getTPL()->assign([ - 'action' => 'add', - 'availableLanguages' => $this->availableLanguages, - 'name' => $this->name, - 'languageID' => $this->languageID, - 'synonyms' => $this->synonyms, - ]); + parent::finalizeForm(); + + $this->form->getDataHandler() + ->addProcessor( + new CustomFormDataProcessor( + 'tagNameProcessor', + static function (IFormDocument $document, array $parameters) { + $parameters['data']['name'] = \str_replace( + ',', + '', + StringUtil::trim($parameters['data']['name']) + ); + + return $parameters; + } + ) + ) + ->addProcessor( + new CustomFormDataProcessor( + 'synonymsProcessor', + null, + static function (IFormDocument $document, array $data, IStorableObject $tag) { + \assert($tag instanceof Tag); + + $synonymList = new TagList(); + $synonymList->getConditionBuilder()->add('synonymFor = ?', [$tag->tagID]); + $synonymList->readObjects(); + $data['synonyms'] = []; + foreach ($synonymList as $synonym) { + $data['synonyms'][] = $synonym->name; + } + + return $data; + } + ) + ); } } diff --git a/wcfsetup/install/files/lib/acp/form/TagEditForm.class.php b/wcfsetup/install/files/lib/acp/form/TagEditForm.class.php index 754a8f5af1..d70b46cbfb 100644 --- a/wcfsetup/install/files/lib/acp/form/TagEditForm.class.php +++ b/wcfsetup/install/files/lib/acp/form/TagEditForm.class.php @@ -2,13 +2,10 @@ namespace wcf\acp\form; +use CuyZ\Valinor\Mapper\MappingError; use wcf\data\tag\Tag; -use wcf\data\tag\TagAction; -use wcf\data\tag\TagEditor; -use wcf\data\tag\TagList; -use wcf\form\AbstractForm; +use wcf\http\Helper; use wcf\system\exception\IllegalLinkException; -use wcf\system\WCF; /** * Shows the tag edit form. @@ -29,123 +26,32 @@ class TagEditForm extends TagAddForm */ public $neededPermissions = ['admin.content.tag.canManageTag']; - /** - * tag id - * @var int - */ - public $tagID = 0; - - /** - * tag object - * @var Tag - */ - public $tagObj; - /** * @inheritDoc */ + public $formAction = 'edit'; + + #[\Override] public function readParameters() { parent::readParameters(); - if (isset($_REQUEST['id'])) { - $this->tagID = \intval($_REQUEST['id']); - } - $this->tagObj = new Tag($this->tagID); - if (!$this->tagObj->tagID) { - throw new IllegalLinkException(); - } - } - - /** - * @inheritDoc - */ - public function save() - { - AbstractForm::save(); - - // update tag - $this->objectAction = new TagAction([$this->tagID], 'update', [ - 'data' => \array_merge($this->additionalFields, [ - 'name' => $this->name, - ]), - ]); - $this->objectAction->executeAction(); - - if ($this->tagObj->synonymFor === null) { - // remove synonyms first - $sql = "UPDATE wcf1_tag - SET synonymFor = ? - WHERE synonymFor = ?"; - $statement = WCF::getDB()->prepare($sql); - $statement->execute([ - null, - $this->tagID, - ]); - - $editor = new TagEditor($this->tagObj); - foreach ($this->synonyms as $synonym) { - if (empty($synonym)) { - continue; - } - - // find existing tag - $synonymObj = Tag::getTag($synonym, $this->tagObj->languageID); - if ($synonymObj === null) { - $synonymAction = new TagAction([], 'create', [ - 'data' => [ - 'name' => $synonym, - 'languageID' => $this->tagObj->languageID, - 'synonymFor' => $this->tagID, - ], - ]); - $synonymAction->executeAction(); - } else { - $editor->addSynonym($synonymObj); - } + try { + $queryParameters = Helper::mapQueryParameters( + $_GET, + <<<'EOT' + array { + id: positive-int + } + EOT + ); + $this->formObject = new Tag($queryParameters['id']); + + if (!$this->formObject->getObjectID()) { + throw new IllegalLinkException(); } + } catch (MappingError) { + throw new IllegalLinkException(); } - - $this->saved(); - - // show success message - WCF::getTPL()->assign('success', true); - } - - /** - * @inheritDoc - */ - public function readData() - { - $this->languageID = $this->tagObj->languageID; - - parent::readData(); - - if (empty($_POST)) { - $this->name = $this->tagObj->name; - $this->languageID = $this->tagObj->languageID; - } - - $synonymList = new TagList(); - $synonymList->getConditionBuilder()->add('synonymFor = ?', [$this->tagObj->tagID]); - $synonymList->readObjects(); - $this->synonyms = []; - foreach ($synonymList as $synonym) { - $this->synonyms[] = $synonym->name; - } - } - - /** - * @inheritDoc - */ - public function assignVariables() - { - parent::assignVariables(); - - WCF::getTPL()->assign([ - 'tagObj' => $this->tagObj, - 'action' => 'edit', - 'synonym' => ($this->tagObj !== null && $this->tagObj->synonymFor) ? new Tag($this->tagObj->synonymFor) : null, - ]); } } diff --git a/wcfsetup/install/files/lib/data/tag/TagAction.class.php b/wcfsetup/install/files/lib/data/tag/TagAction.class.php index cd0dfbb58b..957f87c5bc 100644 --- a/wcfsetup/install/files/lib/data/tag/TagAction.class.php +++ b/wcfsetup/install/files/lib/data/tag/TagAction.class.php @@ -16,9 +16,9 @@ use wcf\system\WCF; * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License * - * @method Tag create() * @method TagEditor[] getObjects() * @method TagEditor getSingleObject() + * @property TagEditor[] $objects */ class TagAction extends AbstractDatabaseObjectAction implements ISearchAction { @@ -66,6 +66,67 @@ class TagAction extends AbstractDatabaseObjectAction implements ISearchAction } } + #[\Override] + public function create() + { + $tag = parent::create(); + \assert($tag instanceof Tag); + + $editor = new TagEditor($tag); + $this->saveSynonyms($editor); + + return $tag; + } + + #[\Override] + public function update() + { + parent::update(); + + foreach ($this->objects as $tagEditor) { + if ($tagEditor->synonymFor !== null) { + continue; + } + + // remove synonyms first + $sql = "UPDATE wcf1_tag + SET synonymFor = ? + WHERE synonymFor = ?"; + $statement = WCF::getDB()->prepare($sql); + $statement->execute([ + null, + $tagEditor->tagID, + ]); + + $this->saveSynonyms($tagEditor); + } + } + + private function saveSynonyms(TagEditor $tagEditor): void + { + $synonyms = $this->parameters['synonyms'] ?? []; + foreach ($synonyms as $synonym) { + if (empty($synonym)) { + continue; + } + + // find existing tag + $synonymObj = Tag::getTag($synonym, $tagEditor->languageID); + if ($synonymObj === null) { + $synonymAction = new TagAction([], 'create', [ + 'data' => [ + 'name' => $synonym, + 'languageID' => $tagEditor->languageID, + 'synonymFor' => $tagEditor->tagID, + ], + ]); + $synonymAction->executeAction(); + } else { + $tagEditor->addSynonym($synonymObj); + } + } + } + /** * @inheritDoc */ -- 2.20.1