Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace I18nHandler with new API #5844

Open
Cyperghost opened this issue Mar 12, 2024 · 0 comments
Open

Replace I18nHandler with new API #5844

Cyperghost opened this issue Mar 12, 2024 · 0 comments
Assignees

Comments

@Cyperghost
Copy link
Contributor

In many cases, working with the I18nHandler generates duplicate and unnecessary code. A new API can reduce this and prevent unnecessary errors.

Current using of I18nHandler

class FooAddForm extends AbstractForm
{
    #[\Override]
    public function validate()
    {
        parent::validate();

        if (!I18nHandler::getInstance()->validateValue('title')) {
            if (I18nHandler::getInstance()->isPlainValue('title')) {
                throw new UserInputException('title');
            } else {
                throw new UserInputException('title', 'multilingual');
            }
        }
    }

    #[\Override]
    public function save()
    {
        parent::save();

        $data = [
            'data' => \array_merge($this->additionalFields, [
                'title' => $this->title,
                …
            ]),
        ];
        $this->objectAction = new FooAction([], 'create', $data);
        $this->objectAction->executeAction();
        $returnValues = $this->objectAction->getReturnValues();
        $fooID = $returnValues['returnValues']->fooID;

        if (!I18nHandler::getInstance()->isPlainValue('title')) {
            I18nHandler::getInstance()->save(
                'title',
                'com.woltlab.foo.title' . $fooID,
                'com.woltlab.foo',
                1
            );

            $fooEditor = new FooEditor($returnValues['returnValues']);
            $fooEditor->update([
                'title' => 'com.woltlab.foo.title' . $fooID,
            ]);
        }

        $this->saved();
        $this->title = '';
        I18nHandler::getInstance()->reset();
    }
}

The developer has to check if the entered values are plain or multilingual.
There is no real reason why the developer needs to check this, and it is not easy to safe the string in the database.

Possible new API class

class I18nField
{
    public function __construct(
        public readonly string $fieldName,
        public readonly string $pattern,
        string|int $languageCategory,
        string|int $package = PACKAGE_ID,
        public readonly bool $requireI18n = false,
        public readonly bool $permitEmptyValue = false,
    );

    /**
     * Initializes the values for this field.
     * If the given value is a string and matches the pattern, the values are loaded from the database,
     * otherwise, the given value is used as the non-multilingual value.
     */
    public function initValues(string|array $value);

    /**
     * Stores the values of this field in the database if the values are multilingual.
     * If the values are multilingual, the given objectID is replaced in the pattern and returned,
     * otherwise the plain value is returned.
     *
     * When the values are non-multilingual, the old language items are removed from the database.
     */
    public function save(int $objectID): string;

    /**
     * Removes language items from the database, matching the given objectIDs in the pattern.
     */
    public static function remove(
        int|array $objectIDs,
        string $pattern,
        string|int $languageCategory,
        string|int $package
    ): void;

    /**
     * Returns true if the values are valid, otherwise a string with the error type is returned.
     *  `empty` is returned if the field is required and the value is empty.
     *  `multilingual` is returned if the field requires multilingual values and one or more values are missing.
     */
    public function validate(): string|bool;

    /**
     * Reads the values from the given request data.
     * If the request data is `null`, the values are read from the `$_POST` array.
     */
    public function readValues(?array $requestData = null): void;

    /**
     * Resets the values of this field.
     */
    public function reset(): void;

    public function getValues(): array;

    /**
     * If the values are multilingual, the value for the default language is returned,
     * otherwise the plain value is returned.
     */
    public function __toString(): string;
}

This also allows bulk deleting and deleting only language items according to the given parameters. #4472

Possible implementation

class FooAddForm extends AbstractForm
{
    public I18nField $title;
    #[\Override]
    public function readParameters()
    {
        parent::readParameters();
        $this->title = new I18nField('title', 'com.woltlab.foo.title\d+', 'com.woltlab.foo', 'com.woltlab.wcf');
    }
    #[\Override]
    public function readFormParameters()
    {
        parent::readFormParameters();
        $this->title->readValues();
    }
    #[\Override]
    public function validate()
    {
        parent::validate();
        if (($errorType = $this->title->validate()) !== true) {
            throw new UserInputException('title', $errorType);
        }
    }

    #[\Override]
    public function save()
    {
        parent::save();
        (new FooAction([], 'create', [
            'data' => \array_merge($this->additionalFields, [
               …
            ]),
            'title' => $this->title,
        ]))->executeAction();
        $this->saved();

        $this->title->reset();
    }
    #[\Override]
    public function assignVariables()
    {
        parent::assignVariables();
        WCF::getTPL()->assign([
            'title' => $this->title,
            …
        ]);
    }
}
class FooAction extends AbstractDatabaseObjectAction
{
    #[\Override]
    public function create()
    {
        $foo = parent::create();
        if (isset($this->parameters['title'])) {
           $fooEditor = new FooEditor($foo);
            \assert($this->parameters['title'] instanceof I18nField);
            $groupEditor->update([
                'title' => $this->parameters['title']->save($foo->fooID),
            ]);
        }
        return $foo;
    }
    #[\Override]
    public function delete()
    {
        if (empty($this->objects)) {
            $this->readObjects();
        }
        $objectIDs = [];
        foreach ($this->getObjects() as $object) {
            $objectIDs[] = $object->getObjectID();
        }
        I18nField::remove($objectIDs, 'com.woltlab.foo.title\d+', 'com.woltlab.foo', 'com.woltlab.wcf');
        return parent::delete();
    }
}
@Cyperghost Cyperghost self-assigned this Mar 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Minor Task
Development

No branches or pull requests

1 participant