Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions com.woltlab.wcf/templates/userOptionFieldList.tpl
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{foreach from=$options item=optionData}
{assign var=option value=$optionData[object]}
<dl class="{$option->optionName}Input{if $errorType|is_array && $errorType[$option->optionName]|isset} formError{/if}">
<dt{if $optionData[cssClassName]} class="{$optionData[cssClassName]}"{/if}>{if $isSearchMode|empty || !$optionData[hideLabelInSearch]}<label for="{$option->optionName}">{$langPrefix|concat:$option->optionName|phrase}</label>{if $isSearchMode|empty && $option->required} <span class="customOptionRequired">*</span>{/if}{/if}</dt>
<dt{if $optionData[cssClassName]} class="{$optionData[cssClassName]}"{/if}>{if $isSearchMode|empty || !$optionData[hideLabelInSearch]}<label for="{$option->optionName}">{$option->getTitle()}</label>{if $isSearchMode|empty && $option->required} <span class="customOptionRequired">*</span>{/if}{/if}</dt>
<dd>{unsafe:$optionData[html]}
<small>{lang __optional=true}{$langPrefix}{$option->optionName}.description{/lang}</small>
<small>{$option->getDescription()}</small>

{if $errorType|is_array && $errorType[$option->optionName]|isset}
<small class="innerError">
Expand Down
4 changes: 2 additions & 2 deletions com.woltlab.wcf/templates/userProfileOptionFieldList.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
{assign var=error value=''}
{/if}
<dl class="{$option->optionName}Input{if $error} formError{/if}">
<dt{if $optionData[cssClassName]} class="{$optionData[cssClassName]}"{/if}><label for="{$option->optionName}">{$langPrefix|concat:$option->optionName|phrase}</label></dt>
<dt{if $optionData[cssClassName]} class="{$optionData[cssClassName]}"{/if}><label for="{$option->optionName}">{$option->getTitle()}</label></dt>
<dd>{unsafe:$optionData[html]}
{if $error}
<small class="innerError">
Expand All @@ -17,7 +17,7 @@
{/if}
</small>
{/if}
<small>{lang __optional=true}{$langPrefix}{$option->optionName}.description{/lang}</small>
<small>{$option->getDescription()}</small>
</dd>
</dl>
{/foreach}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

/**
* Drops the captcha question columns that have been migrated into the
* `wcf1_captcha_question_l10n` table.
*
* IMPORTANT ordering constraint for package.xml: This script must run AFTER
* the data migration in `acp/update_com.woltlab.wcf_6.3_captchaQuestionL10n.php`.
*/

use wcf\system\database\table\column\MediumtextDatabaseTableColumn;
use wcf\system\database\table\column\NotNullVarchar255DatabaseTableColumn;
use wcf\system\database\table\PartialDatabaseTable;

return [
PartialDatabaseTable::create('wcf1_captcha_question')
->columns([
NotNullVarchar255DatabaseTableColumn::create('question')->drop(),
MediumtextDatabaseTableColumn::create('answers')->drop(),
]),
];
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,18 @@

use wcf\system\database\table\column\CharDatabaseTableColumn;
use wcf\system\database\table\column\DefaultFalseBooleanDatabaseTableColumn;
use wcf\system\database\table\column\IntDatabaseTableColumn;
use wcf\system\database\table\column\JsonDatabaseTableColumn;
use wcf\system\database\table\column\MediumintDatabaseTableColumn;
use wcf\system\database\table\column\MediumtextDatabaseTableColumn;
use wcf\system\database\table\column\NotNullInt10DatabaseTableColumn;
use wcf\system\database\table\column\NotNullVarchar255DatabaseTableColumn;
use wcf\system\database\table\column\SmallintDatabaseTableColumn;
use wcf\system\database\table\column\TextDatabaseTableColumn;
use wcf\system\database\table\column\VarcharDatabaseTableColumn;
use wcf\system\database\table\DatabaseTable;
use wcf\system\database\table\index\DatabaseTableForeignKey;
use wcf\system\database\table\index\DatabaseTableIndex;
use wcf\system\database\table\PartialDatabaseTable;

return [
Expand Down Expand Up @@ -74,4 +81,30 @@
->defaultValue('')
->drop(),
]),
DatabaseTable::create('wcf1_captcha_question_l10n')
->columns([
NotNullInt10DatabaseTableColumn::create('questionID'),
IntDatabaseTableColumn::create('languageID'),
VarcharDatabaseTableColumn::create('question')
->length(255),
MediumtextDatabaseTableColumn::create('answers'),
])
->indices([
DatabaseTableIndex::create('questionID')
->columns(['questionID', 'languageID']),
])
->foreignKeys([
DatabaseTableForeignKey::create()
->columns(['questionID'])
->referencedTable('wcf1_captcha_question')
->referencedColumns(['questionID'])
->onDelete('CASCADE')
->onUpdate('NO ACTION'),
DatabaseTableForeignKey::create()
->columns(['languageID'])
->referencedTable('wcf1_language')
->referencedColumns(['languageID'])
->onDelete('CASCADE')
->onUpdate('NO ACTION'),
]),
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

/**
* Adds the `l10nIdentifier` column to `wcf1_user_option` and creates the
* `wcf1_user_option_l10n` table that stores the localized title and description
* of a user option.
*
* IMPORTANT ordering constraint for package.xml: This script must run BEFORE
* the data migration in `acp/update_com.woltlab.wcf_6.3_userOptionL10n.php`.
*/

use wcf\system\database\table\column\IntDatabaseTableColumn;
use wcf\system\database\table\column\MediumtextDatabaseTableColumn;
use wcf\system\database\table\column\NotNullInt10DatabaseTableColumn;
use wcf\system\database\table\column\TinyintDatabaseTableColumn;
use wcf\system\database\table\column\VarcharDatabaseTableColumn;
use wcf\system\database\table\DatabaseTable;
use wcf\system\database\table\index\DatabaseTableForeignKey;
use wcf\system\database\table\index\DatabaseTableIndex;
use wcf\system\database\table\PartialDatabaseTable;

return [
PartialDatabaseTable::create('wcf1_user_option')
->columns([
VarcharDatabaseTableColumn::create('l10nIdentifier')
->length(255),
]),
DatabaseTable::create('wcf1_user_option_l10n')
->columns([
NotNullInt10DatabaseTableColumn::create('optionID'),
IntDatabaseTableColumn::create('languageID'),
VarcharDatabaseTableColumn::create('title')
->length(255),
MediumtextDatabaseTableColumn::create('description'),
TinyintDatabaseTableColumn::create('isPristine')
->notNull()
->defaultValue(1),
])
->indices([
DatabaseTableIndex::create('optionID')
->columns(['optionID', 'languageID']),
])
->foreignKeys([
DatabaseTableForeignKey::create()
->columns(['optionID'])
->referencedTable('wcf1_user_option')
->referencedColumns(['optionID'])
->onDelete('CASCADE')
->onUpdate('NO ACTION'),
DatabaseTableForeignKey::create()
->columns(['languageID'])
->referencedTable('wcf1_language')
->referencedColumns(['languageID'])
->onDelete('CASCADE')
->onUpdate('NO ACTION'),
]),
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

/**
* Migrates the captcha question values (`question` and `answers`) from the
* columns of `wcf1_captcha_question` (literal values or i18n phrases) into the
* `wcf1_captcha_question_l10n` table.
*
* IMPORTANT ordering constraints for package.xml:
* - The database script `acp/database/update_com.woltlab.wcf_6.3_step1.php`
* (creating the `wcf1_captcha_question_l10n` table) must run BEFORE this script.
* - The database script `acp/database/update_com.woltlab.wcf_6.3_captchaQuestion.php`
* (dropping the migrated columns) must run AFTER this script.
*/

use wcf\data\captcha\question\CaptchaQuestion;
use wcf\system\cache\builder\CaptchaQuestionCacheBuilder;
use wcf\system\l10n\L10nLanguageItemSource;
use wcf\system\l10n\L10nLanguageItemSync;
use wcf\system\WCF;

// This script owns the table's content at this point (idempotency on re-runs).
WCF::getDB()->prepare("DELETE FROM wcf1_captcha_question_l10n")->execute();

L10nLanguageItemSync::migrate(
CaptchaQuestion::getL10nDefinition(),
static function (array $row): array {
$questionIsPhrase = (bool)\preg_match(
'~^wcf\.captcha\.question\.question\.question\d+$~',
$row['question']
);
$answersIsPhrase = $row['answers'] !== null && (bool)\preg_match(
'~^wcf\.captcha\.question\.answers\.question\d+$~',
$row['answers']
);

return [
'sources' => [
'question' => new L10nLanguageItemSource(
languageItem: $questionIsPhrase ? $row['question'] : null,
literal: $row['question'],
deleteAfterMigration: true,
),
'answers' => new L10nLanguageItemSource(
languageItem: $answersIsPhrase ? $row['answers'] : null,
literal: $row['answers'],
deleteAfterMigration: true,
),
],
];
}
);

// Cached question objects were created without their localized values.
CaptchaQuestionCacheBuilder::getInstance()->reset();
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

/**
* Migrates the localized title and description of user options from the
* `wcf.user.option.<optionName>[.description]` language variables into the
* `wcf1_user_option_l10n` table.
*
* System options (shipped by a package) are linked to their language variable
* via `l10nIdentifier`; their localized values are stored as pristine copies
* and kept in sync with the phrases. Options created by an administrator
* (`option<id>`) own their localized value: they stay unlinked and their
* obsolete phrases are removed.
*
* IMPORTANT ordering constraint for package.xml: The database script
* `acp/database/update_com.woltlab.wcf_6.3_userOption.php` (adding the
* `l10nIdentifier` column and creating the `wcf1_user_option_l10n` table) must
* run BEFORE this script.
*/

use wcf\data\user\option\UserOption;
use wcf\system\cache\builder\UserOptionCacheBuilder;
use wcf\system\l10n\L10nLanguageItemSource;
use wcf\system\l10n\L10nLanguageItemSync;
use wcf\system\WCF;

$isAdminCreated = static fn(string $optionName): bool => (bool)\preg_match('/^option\d+$/', $optionName);

// This script owns the table's content at this point (idempotency on re-runs).
WCF::getDB()->prepare("DELETE FROM wcf1_user_option_l10n")->execute();

// Link system options to their language variable; administrator created
// options own their localized value and stay unlinked.
$statement = WCF::getDB()->prepare("SELECT optionID, optionName FROM wcf1_user_option");
$statement->execute();
$updateStatement = WCF::getDB()->prepare(
"UPDATE wcf1_user_option SET l10nIdentifier = ? WHERE optionID = ?"
);
while ($row = $statement->fetchArray()) {
$updateStatement->execute([
$isAdminCreated($row['optionName']) ? null : 'wcf.user.option.' . $row['optionName'],
$row['optionID'],
]);
}

// Migrate the phrase values into the l10n storage.
L10nLanguageItemSync::migrate(
UserOption::getL10nDefinition(),
static function (array $row) use ($isAdminCreated): array {
$adminCreated = $isAdminCreated($row['optionName']);
$identifier = 'wcf.user.option.' . $row['optionName'];

return [
'sources' => [
'title' => new L10nLanguageItemSource(
languageItem: $identifier,
deleteAfterMigration: $adminCreated,
),
'description' => new L10nLanguageItemSource(
languageItem: $identifier . '.description',
deleteAfterMigration: $adminCreated,
),
],
];
}
);

UserOptionCacheBuilder::getInstance()->reset();
Loading
Loading