</nav>
</header>
-{include file='shared_formNotice'}
-
-<form method="post" action="{if $action == 'add'}{link controller='TagAdd'}{/link}{else}{link controller='TagEdit' object=$tagObj}{/link}{/if}">
- <div class="section">
- <dl{if $errorField == 'name'} class="formError"{/if}>
- <dt><label for="name">{lang}wcf.global.name{/lang}</label></dt>
- <dd>
- <input type="text" id="name" name="name" value="{$name}" required autofocus class="long">
- {if $errorField == 'name'}
- <small class="innerError">
- {if $errorType == 'empty'}
- {lang}wcf.global.form.error.empty{/lang}
- {elseif $errorType == 'duplicate'}
- {lang}wcf.acp.tag.error.name.duplicate{/lang}
- {/if}
- </small>
- {/if}
- </dd>
- </dl>
-
- {hascontent}
- <dl{if $errorField == 'languageID' || $action == 'edit'} class="{if $action == 'edit'}disabled{else}formError{/if}"{/if}>
- <dt><label for="languageID">{lang}wcf.acp.tag.languageID{/lang}</label></dt>
- <dd>
- <select id="languageID" name="languageID"{if $action == 'edit'} disabled{/if}>
- {content}
- {foreach from=$availableLanguages item=language}
- <option value="{$language->languageID}"{if $languageID == $language->languageID} selected{/if}>{$language->languageName} ({$language->languageCode})</option>
- {/foreach}
- {/content}
- </select>
- {if $errorField == 'languageID'}
- <small class="innerError">
- {lang}wcf.acp.tag.error.languageID.{$errorType}{/lang}
- </small>
- {/if}
- </dd>
- </dl>
- {/hascontent}
-
- {if !$tagObj|isset || $tagObj->synonymFor === null}
- <dl>
- <dt><label for="synonyms">{lang}wcf.acp.tag.synonyms{/lang}</label></dt>
- <dd>
- <input id="synonyms" type="text" value="" class="long">
- </dd>
- </dl>
-
- <script data-relocate="true">
- require(['WoltLabSuite/Core/Ui/ItemList'], function(UiItemList) {
- UiItemList.init(
- 'synonyms',
- [{if !$synonyms|empty}{implode from=$synonyms item=synonym}'{$synonym|encodeJS}'{/implode}{/if}],
- {
- ajax: {
- className: 'wcf\\data\\tag\\TagAction'
- },
- maxLength: {@TAGGING_MAX_TAG_LENGTH},
- submitFieldName: 'tags[]'
- }
- );
- });
- </script>
- {elseif $tagObj|isset}
- <dl>
- <dt><label for="synonyms">{lang}wcf.acp.tag.synonymFor{/lang}</label></dt>
- <dd>
- <a href="{link controller='TagEdit' id=$tagObj->synonymFor}{/link}" class="badge tag">{$synonym->name}</a>
- </dd>
- </dl>
- {/if}
-
- {event name='dataFields'}
- </div>
-
- {event name='sections'}
-
- <div class="formSubmit">
- <input type="submit" value="{lang}wcf.global.button.submit{/lang}" accesskey="s">
- {csrfToken}
- </div>
-</form>
+{unsafe:$form->getHtml()}
{include file='footer'}
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 <http://opensource.org/licenses/lgpl-license.php>
+ * @author Olaf Braun, Tim Duesterhus
+ * @copyright 2001-2024 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ *
+ * @property Tag $formObject
*/
-class TagAddForm extends AbstractForm
+class TagAddForm extends AbstractFormBuilderForm
{
/**
* @inheritDoc
*/
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;
+ }
+ )
+ );
}
}
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.
*/
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,
- ]);
}
}