From 21339605e67d1cfdbc1a34e1dd3986f9443b04ca Mon Sep 17 00:00:00 2001 From: j3nsch Date: Mon, 4 May 2026 15:23:32 +0200 Subject: [PATCH 1/9] #867 Use database for editable config options --- application/configs/options.yml | 9 +++ composer.json | 2 +- library/Application/Bootstrap.php | 13 +++ .../admin/controllers/ConfigController.php | 5 +- modules/admin/forms/Configuration.php | 74 +++++++++++------ modules/admin/language/config.tmx | 27 ++++--- modules/admin/models/Option.php | 80 ++++++++++++------- modules/admin/models/Options.php | 35 +++----- modules/admin/models/options.json | 18 ----- .../setup/controllers/LanguageController.php | 2 - public/index.php | 8 -- scripts/update/021-Move-config-xml-to-db.php | 76 ++++++++++++++++++ .../modules/admin/forms/ConfigurationTest.php | 20 ++++- tests/modules/admin/models/OptionTest.php | 12 +-- tests/modules/admin/models/OptionsTest.php | 2 +- 15 files changed, 255 insertions(+), 128 deletions(-) create mode 100644 application/configs/options.yml delete mode 100644 modules/admin/models/options.json create mode 100755 scripts/update/021-Move-config-xml-to-db.php diff --git a/application/configs/options.yml b/application/configs/options.yml new file mode 100644 index 000000000..4652309ad --- /dev/null +++ b/application/configs/options.yml @@ -0,0 +1,9 @@ +searchengine.solr.parameterDefaults.rows: + type: int + section: searching + options: + min: 10 + +browsing.series.sortByTitle: + type: bool + section: browsing diff --git a/composer.json b/composer.json index 787b8eaa2..236a65104 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "opus4/zf1-future": "1.25.*", "jpgraph/jpgraph": "dev-master", "opus4-repo/opus4-common": "^4.9", - "opus4-repo/framework": "^4.9", + "opus4-repo/framework": "dev-master as 4.10", "opus4-repo/search": "^4.9", "opus4-repo/opus4-bibtex": "^4.9", "opus4-repo/opus4-import": "^4.9", diff --git a/library/Application/Bootstrap.php b/library/Application/Bootstrap.php index 4ed1957ab..1100dd953 100644 --- a/library/Application/Bootstrap.php +++ b/library/Application/Bootstrap.php @@ -30,9 +30,11 @@ */ use Opus\App\Common\Configuration; +use Opus\Common\Config; use Opus\Common\Log\LogService; use Opus\Common\Repository; use Opus\Db\DatabaseBootstrap; +use Opus\Db2\Configuration as ConfigurationDatabase; use Opus\Search\Plugin\Index; /** @@ -411,4 +413,15 @@ protected function _initIndexPlugin() // TODO this is a dependency on a specific implementation (refactor to remove) $cache::setIndexPluginClass(Index::class); } + + protected function _initOnlineConfiguration() + { + $this->bootstrap('Database'); + + $configuration = new ConfigurationDatabase(); + $onlineConfig = $configuration->getConfig(); + + $config = Config::get(); + $config->merge($onlineConfig); + } } diff --git a/modules/admin/controllers/ConfigController.php b/modules/admin/controllers/ConfigController.php index 167eace80..032f5bf15 100644 --- a/modules/admin/controllers/ConfigController.php +++ b/modules/admin/controllers/ConfigController.php @@ -29,8 +29,6 @@ * @license http://www.gnu.org/licenses/gpl.html General Public License */ -use Opus\App\Common\Configuration; - class Admin_ConfigController extends Application_Controller_Action { public function indexAction() @@ -48,8 +46,7 @@ public function indexAction() case Admin_Form_Configuration::RESULT_SAVE: if ($form->isValid($data)) { $config = new Zend_Config([], true); - $form->updateModel($config); - Configuration::save($config); + $form->updateModel($config); // TODO $config object is not needed } else { break; } diff --git a/modules/admin/forms/Configuration.php b/modules/admin/forms/Configuration.php index b65dcbd60..6d973a2a3 100644 --- a/modules/admin/forms/Configuration.php +++ b/modules/admin/forms/Configuration.php @@ -33,25 +33,20 @@ /** * Form for editing selected OPUS 4 configuration options. - * - * TODO Application_Form_Abstract should be enough (not ID element needed) */ class Admin_Form_Configuration extends Application_Form_Model_Abstract { /** * Prefix for translation keys of configuration options. * - * TODO wird auf von Admin_Model_Option verwendet + * TODO wird auch von Admin_Model_Option verwendet */ public const LABEL_TRANSLATION_PREFIX = 'admin_config_'; /** @var array Configured options for form. */ private $options; - /** - * @param null|Zend_Config $config - */ - public function __construct($config = null) + public function __construct(?array $config = null) { if ($config !== null) { $options = new Admin_Model_Options($config); @@ -73,19 +68,27 @@ public function init() $this->options = $options->getOptions(); } - foreach ($this->options as $name => $option) { + foreach ($this->options as $option) { $section = $option->getSection(); + $elementOptions = $option->getOptions(); + + $translator = $this->getTranslator(); + + if ($translator->isTranslated($option->getDescription())) { + $elementOptions['description'] = $option->getDescription(); + } + + if ($translator->isTranslated($option->getLabel())) { + $elementOptions['label'] = $option->getLabel(); + } else { + $elementOptions['label'] = $option->getKey(); + } + $element = $this->createElement( $option->getElementType(), - $name, - array_merge( - [ - 'label' => $option->getLabel(), - 'description' => $option->getDescription(), - ], - $option->getOptions() - ) + $option->getElementId(), + $elementOptions ); $this->addElement($element); @@ -95,6 +98,8 @@ public function init() $this->removeElement(self::ELEMENT_MODEL_ID); $this->setAttrib('class', 'admin_config'); + + $this->sortSections(); } /** @@ -104,9 +109,9 @@ public function init() */ public function populateFromModel($config) { - foreach ($this->options as $name => $option) { + foreach ($this->options as $option) { $value = Configuration::getValueFromConfig($config, $option->getKey()); - $this->getElement($name)->setValue($value); + $this->getElement($option->getElementId())->setValue($value); } } @@ -117,15 +122,18 @@ public function populateFromModel($config) */ public function updateModel($config) { - foreach ($this->options as $name => $option) { - $value = $this->getElement($name)->getValue(); + foreach ($this->options as $option) { + $value = $this->getElement($option->getElementId())->getValue(); // TODO move into Admin_Model_Option? if (is_array($value)) { $value = implode(',', $value); } + if (strlen(trim($value)) === 0) { + $value = null; + } - Configuration::setValueInConfig($config, $option->getKey(), $value); + $option->setValue($value); } } @@ -134,11 +142,9 @@ public function updateModel($config) * * If necessary a new display group is created. * - * @param Zend_Form_Element $element Form element - * @param string $section Name of section * @throws Zend_Form_Exception */ - public function addElementToSection($element, $section) + public function addElementToSection(Zend_Form_Element $element, string $section): void { $group = $this->getDisplayGroup($section); @@ -155,4 +161,24 @@ public function addElementToSection($element, $section) $group->addElement($element); } } + + public function sortSections(): void + { + $groups = $this->getDisplayGroups(); + + $names = array_keys($groups); + unset($names['actions']); + + sort($names); + + $sorted = []; + + foreach ($names as $section) { + $sorted[$section] = $groups[$section]; + } + + $sorted['actions'] = $groups['actions']; + + $this->setDisplayGroups($sorted); + } } diff --git a/modules/admin/language/config.tmx b/modules/admin/language/config.tmx index 98bb735bb..1211c5130 100644 --- a/modules/admin/language/config.tmx +++ b/modules/admin/language/config.tmx @@ -26,7 +26,7 @@ - + Search @@ -53,25 +53,34 @@ + + + Languages + + + Sprachen + + + - Supported Languages + User Interface Languages - Unterstützte Sprachen + Weboberfläche Sprachen - Languages for the user interface. Select at least one. + Languages for the user interface. Select at least one (e.g. 'en'). - Sprachen für die Benutzeroberfläche. Mindestens eine auswählen. + Sprachen für die Benutzeroberfläche. Mindestens eine angeben (z.B. 'de'). - + Default search results/page @@ -80,7 +89,7 @@ - + Number of results that should be display on a single page. @@ -89,7 +98,7 @@ - + Sort series by title @@ -98,7 +107,7 @@ - + Activates alphabetical sorting of series in browsing list and publish form. diff --git a/modules/admin/models/Option.php b/modules/admin/models/Option.php index 30f61032f..3ad0af9ba 100644 --- a/modules/admin/models/Option.php +++ b/modules/admin/models/Option.php @@ -29,58 +29,53 @@ * @license http://www.gnu.org/licenses/gpl.html General Public License */ +use Opus\Db2\Configuration; + class Admin_Model_Option extends Application_Model_Abstract { /** @var string Name of configuration option. */ - private $name; + private $key; /** @var array Parameters for option. */ private $config; - /** - * @param string $name Name of option - * @param array $config Parameters for option - */ - public function __construct($name, $config) + public function __construct(string $key, array $config) { - $this->name = $name; + $this->key = $key; $this->config = $config; } /** - * @return string + * Returns option key. */ - public function getName() + public function getKey(): string { - return $this->name; + return $this->key; } /** - * @return string + * Returns translation key for option label. */ - public function getKey() + public function getLabel(): string { - return $this->config['key']; + return Admin_Form_Configuration::LABEL_TRANSLATION_PREFIX . $this->key; } /** - * Returns label name for option. - * - * @return string + * Returns translation key for option description. */ - public function getLabel() + public function getDescription(): string { - return Admin_Form_Configuration::LABEL_TRANSLATION_PREFIX . $this->name; + return Admin_Form_Configuration::LABEL_TRANSLATION_PREFIX . $this->key . '_description'; } - /** - * Returns translation key for option description. - * - * @return string - */ - public function getDescription() + public function getType(): string { - return Admin_Form_Configuration::LABEL_TRANSLATION_PREFIX . $this->name . '_description'; + if (isset($this->config['type'])) { + return $this->config['type']; + } + + return 'text'; } /** @@ -90,13 +85,27 @@ public function getDescription() */ public function getElementType() { - if (isset($this->config['type'])) { - $type = $this->config['type']; - } else { + $type = $this->getType(); + + if (null === $type) { $type = 'text'; } - return $type; + switch ($this->getType()) { + case 'int': + return 'number'; + case 'bool': + return 'checkbox'; + case 'string': + return 'text'; + default: + return $type; + } + } + + public function getElementId(): string + { + return str_replace('.', '_', $this->getKey()); } /** @@ -128,4 +137,17 @@ public function getOptions() return []; } } + + public function getValue(): string + { + $configuration = new Configuration(); + return $configuration->getOption($this->getKey()); + } + + public function setValue(?string $value): self + { + $configuration = new Configuration(); + $configuration->setOption($this->getKey(), $value); + return $this; + } } diff --git a/modules/admin/models/Options.php b/modules/admin/models/Options.php index 6d07df5de..c2a1f20f3 100644 --- a/modules/admin/models/Options.php +++ b/modules/admin/models/Options.php @@ -38,54 +38,41 @@ class Admin_Model_Options extends Application_Model_Abstract /** * Path to options configuration. */ - public const OPTIONS_CONFIG_FILE = '/modules/admin/models/options.json'; + public const OPTIONS_CONFIG_FILE = '/application/configs/options.yml'; /** @var array Option objects. */ private $options; - /** @var Zend_Config */ + /** @var array */ private $config; - /** - * @param Zend_Config|null $config - * - * TODO allow providing Zend_Config object - */ - public function __construct($config = null) + public function __construct(?array $config = null) { - if ($config !== null && is_array($config)) { - $this->config = new Zend_Config($config); - } + $this->config = $config; } /** * Returns options configuration from file. - * - * @return array */ - public function getOptions() + public function getOptions(): array { if ($this->options === null) { $this->options = []; - $config = $this->getConfig(); - $options = $config->toArray(); - foreach ($options as $name => $parameters) { - $this->options[$name] = new Admin_Model_Option($name, $parameters); + $config = $this->getConfig(); + + foreach ($config as $optionKey => $parameters) { + $this->options[$optionKey] = new Admin_Model_Option($optionKey, $parameters); } } return $this->options; } - /** - * @return Zend_Config - * @throws Zend_Config_Exception - */ - public function getConfig() + public function getConfig(): array { if ($this->config === null) { - $this->config = new Zend_Config_Json(APPLICATION_PATH . self::OPTIONS_CONFIG_FILE); + $this->config = yaml_parse_file(APPLICATION_PATH . self::OPTIONS_CONFIG_FILE); } return $this->config; diff --git a/modules/admin/models/options.json b/modules/admin/models/options.json deleted file mode 100644 index 24565c4a7..000000000 --- a/modules/admin/models/options.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "maxSearchResults": { - "key": "searchengine.solr.parameterDefaults.rows", - "type": "number", - "section": "searchopt", - "options": { - "min": 10, - "required": "true" - } - }, - "seriesSortByTitle": { - "key": "browsing.series.sortByTitle", - "type": "checkbox", - "section": "browsing" - } -} - - diff --git a/modules/setup/controllers/LanguageController.php b/modules/setup/controllers/LanguageController.php index 537f2adca..a51898db4 100644 --- a/modules/setup/controllers/LanguageController.php +++ b/modules/setup/controllers/LanguageController.php @@ -495,7 +495,6 @@ public function settingsAction() $form = new Admin_Form_Configuration([ 'supportedLanguages' => [ - 'key' => 'activatedLanguages', 'type' => 'supportedLanguages', 'section' => 'general', ], @@ -513,7 +512,6 @@ public function settingsAction() if ($form->isValid($data)) { $config = new Zend_Config([], true); $form->updateModel($config); - Configuration::save($config); } else { break; } diff --git a/public/index.php b/public/index.php index 9d0bc9982..250fdf0cf 100644 --- a/public/index.php +++ b/public/index.php @@ -71,14 +71,6 @@ $config->merge($localConfig); -// configuration file that is modified via application user interface -if (is_readable(APPLICATION_PATH . '/application/configs/config.xml')) { - $onlineConfig = new Zend_Config_Xml( - APPLICATION_PATH . '/application/configs/config.xml' - ); - $config->merge($onlineConfig); -} - // Create application, bootstrap, and run $application = new Zend_Application(APPLICATION_ENV, $config); diff --git a/scripts/update/021-Move-config-xml-to-db.php b/scripts/update/021-Move-config-xml-to-db.php new file mode 100755 index 000000000..1e1cd8c32 --- /dev/null +++ b/scripts/update/021-Move-config-xml-to-db.php @@ -0,0 +1,76 @@ +writeln("Importing '{$configPath}' into database."); + +if (! is_readable($configPath)) { + $output->writeln('File \'' . $configPath . '\' is not readable.'); + exit(); +} + +// Import options from config.xml +$config = new Zend_Config_Xml($configPath); +$configDatabase = new Configuration(); +$configDatabase->import($config, true); + +// Show imported options +$imported = $configDatabase->getConfig(); +if (count($imported) > 0) { + $options = $configDatabase->arr2ini($imported->toArray()); + $output->writeln('Imported options:'); + foreach ($options as $key => $value) { + $output->writeln(' ' . $key . ' = ' . $value); + } +} + +// Remove config.xml file +$helper = new Application_Update_Helper(); + +if ($helper->askYesNo("Delete '{$configPath}' file [Y/n]?", true)) { + $output->write("Removeing '{$configPath}' file ... "); + $filesystem = new Filesystem(); + $filesystem->remove($configPath); + $output->writeln('done'); +} diff --git a/tests/modules/admin/forms/ConfigurationTest.php b/tests/modules/admin/forms/ConfigurationTest.php index 3a3a844ed..0d1d2b774 100644 --- a/tests/modules/admin/forms/ConfigurationTest.php +++ b/tests/modules/admin/forms/ConfigurationTest.php @@ -29,6 +29,8 @@ * @license http://www.gnu.org/licenses/gpl.html General Public License */ +use Opus\Db2\Configuration; + class Admin_Form_ConfigurationTest extends ControllerTestCase { /** @var string[] */ @@ -51,7 +53,7 @@ public function testPopulateFromModel() 'searchengine' => ['solr' => ['parameterDefaults' => ['rows' => '20']]], ])); // searchengine.solr.parameterDefaults.rows - $element = $form->getElement('maxSearchResults'); + $element = $form->getElement('searchengine_solr_parameterDefaults_rows'); $this->assertNotNull($element); $this->assertEquals(20, $element->getValue()); @@ -61,13 +63,16 @@ public function testUpdateModel() { $form = new Admin_Form_Configuration(); - $form->getElement('maxSearchResults')->setValue(15); + $form->getElement('searchengine_solr_parameterDefaults_rows')->setValue(15); $config = new Zend_Config([], true); $form->updateModel($config); - $this->assertEquals(15, $config->searchengine->solr->parameterDefaults->rows); + $configDatabase = new Configuration(); + $this->assertEquals(15, $configDatabase->getOption( + 'searchengine.solr.parameterDefaults.rows' + )); } public function testValidationSuccess() @@ -88,4 +93,13 @@ public function testValidationFailure() 'supportedLanguages' => ['ru'], ])); } + + public function testLoadOptionsConfig() + { + $optionsConfigPath = APPLICATION_PATH . '/application/configs/options.yml'; + + $options = yaml_parse_file($optionsConfigPath); + + $this->assertIsArray($options); + } } diff --git a/tests/modules/admin/models/OptionTest.php b/tests/modules/admin/models/OptionTest.php index da7ec993d..03ad499ad 100644 --- a/tests/modules/admin/models/OptionTest.php +++ b/tests/modules/admin/models/OptionTest.php @@ -38,8 +38,7 @@ public function setUp(): void { parent::setUp(); - $this->model = new Admin_Model_Option('test', [ - 'key' => 'supportedLanguages', + $this->model = new Admin_Model_Option('supportedLanguages', [ 'type' => 'number', 'section' => 'search', 'options' => [ @@ -86,20 +85,23 @@ public function testGetDefaultElementType() public function testGetLabel() { - $this->assertEquals(Admin_Form_Configuration::LABEL_TRANSLATION_PREFIX . 'test', $this->model->getLabel()); + $this->assertEquals( + Admin_Form_Configuration::LABEL_TRANSLATION_PREFIX . 'supportedLanguages', + $this->model->getLabel() + ); } public function testGetDescription() { $this->assertEquals( - Admin_Form_Configuration::LABEL_TRANSLATION_PREFIX . 'test_description', + Admin_Form_Configuration::LABEL_TRANSLATION_PREFIX . 'supportedLanguages_description', $this->model->getDescription() ); } public function testGetName() { - $this->assertEquals('test', $this->model->getName()); + $this->assertEquals('supportedLanguages', $this->model->getKey()); } public function testGetKey() diff --git a/tests/modules/admin/models/OptionsTest.php b/tests/modules/admin/models/OptionsTest.php index e74f4c855..aaa63be32 100644 --- a/tests/modules/admin/models/OptionsTest.php +++ b/tests/modules/admin/models/OptionsTest.php @@ -50,7 +50,7 @@ public function testGetOptions() foreach ($options as $name => $option) { $this->assertInstanceOf(Admin_Model_Option::class, $option); - $this->assertEquals($name, $option->getName()); + $this->assertEquals($name, $option->getKey()); } } } From 4bbdeb2e640e02b62a087c3fe389f21832c31f28 Mon Sep 17 00:00:00 2001 From: j3nsch Date: Mon, 4 May 2026 15:40:25 +0200 Subject: [PATCH 2/9] #867 Update OPUS 4 internal version --- db/masterdata/022-set-opus-version.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/masterdata/022-set-opus-version.sql b/db/masterdata/022-set-opus-version.sql index 9af826166..9c81e0eb0 100644 --- a/db/masterdata/022-set-opus-version.sql +++ b/db/masterdata/022-set-opus-version.sql @@ -11,7 +11,7 @@ START TRANSACTION; -- Set internal OPUS version (for controlling updates) TRUNCATE TABLE `opus_version`; -INSERT INTO `opus_version` (`version`) VALUES (20); +INSERT INTO `opus_version` (`version`) VALUES (21); COMMIT; From ded3e544da1b3f47115ad3f699350321f3dedbd7 Mon Sep 17 00:00:00 2001 From: j3nsch Date: Mon, 4 May 2026 16:12:49 +0200 Subject: [PATCH 3/9] #867 Fixed validation tests --- tests/modules/admin/forms/ConfigurationTest.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/modules/admin/forms/ConfigurationTest.php b/tests/modules/admin/forms/ConfigurationTest.php index 0d1d2b774..1a24799e8 100644 --- a/tests/modules/admin/forms/ConfigurationTest.php +++ b/tests/modules/admin/forms/ConfigurationTest.php @@ -80,8 +80,7 @@ public function testValidationSuccess() $form = new Admin_Form_Configuration(); $this->assertTrue($form->isValid([ - 'supportedLanguages' => ['de'], - 'maxSearchResults' => '10', + 'searchengine_solr_parameterDefaults_rows' => '10', ])); } @@ -90,7 +89,7 @@ public function testValidationFailure() $form = new Admin_Form_Configuration(); $this->assertFalse($form->isValid([ - 'supportedLanguages' => ['ru'], + 'searchengine_solr_parameterDefaults_rows' => '5', ])); } From 120eb4cd7d74bfe844cd6e1264db1e4cc1104341 Mon Sep 17 00:00:00 2001 From: j3nsch Date: Mon, 4 May 2026 16:15:24 +0200 Subject: [PATCH 4/9] #867 Remove useless use statement --- modules/setup/controllers/LanguageController.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/setup/controllers/LanguageController.php b/modules/setup/controllers/LanguageController.php index a51898db4..41a2f3b3a 100644 --- a/modules/setup/controllers/LanguageController.php +++ b/modules/setup/controllers/LanguageController.php @@ -29,8 +29,6 @@ * @license http://www.gnu.org/licenses/gpl.html General Public License */ -use Opus\App\Common\Configuration; - /** * TODO rename controller to TranslationController * TODO sorting using table header From 56f3516b204d80e0e00c0867252d112bd8c56e48 Mon Sep 17 00:00:00 2001 From: j3nsch Date: Mon, 4 May 2026 17:17:52 +0200 Subject: [PATCH 5/9] #867 Added to release notes --- RELEASE_NOTES.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 65a684b40..74dead2df 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -2,6 +2,24 @@ ## Release 4.10 - 2026-05-12 +### Update + +Das Updateskript muss ausgeführt werden, da es Änderungen an der Datenbank und +zusätzliche Updateschritte gibt. + +### Konfiguration + +Bislang sind nur wenige Optionen in der Administration editierbar. Diese wurde +bisher in `application/configs/config.xml` gespeichert. Dafür gibt es jetzt eine +Tabelle in der Datenbank. Beim Update wird der Inhalt von `config.xml` in die +Datenbank übertragen und die Datei dann (optional) gelöscht. + +Die editierbaren Optionen werden nun in `application/configs/options.yml` +definiert. Generell kann die Liste lokal erweitert werden. Im Standard werden +im Laufe der Zeit mehr Optionen in der Weboberfläche verfügbar gemacht werden. + +TODO Link to documentation + ### RSS-Links RSS-Links können nun ausgeblendet werden. Sie werden automatisch ausgeblendet, From 3788e39efddb512447bb4298934aafeb5a9db77b Mon Sep 17 00:00:00 2001 From: j3nsch Date: Mon, 4 May 2026 17:23:37 +0200 Subject: [PATCH 6/9] #867 Use section name as fallback if translation is missing --- modules/admin/forms/Configuration.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/modules/admin/forms/Configuration.php b/modules/admin/forms/Configuration.php index 6d973a2a3..8d850fa7b 100644 --- a/modules/admin/forms/Configuration.php +++ b/modules/admin/forms/Configuration.php @@ -148,12 +148,19 @@ public function addElementToSection(Zend_Form_Element $element, string $section) { $group = $this->getDisplayGroup($section); + $translator = $this->getTranslator(); + $sectionKey = self::LABEL_TRANSLATION_PREFIX . 'section_' . $section; + + if (! $translator->isTranslated($sectionKey)) { + $sectionKey = ucfirst($section); + } + if ($group === null) { $this->addDisplayGroup( [$element], $section, [ - 'legend' => self::LABEL_TRANSLATION_PREFIX . 'section_' . $section, + 'legend' => $sectionKey, 'decorators' => ['FormElements', 'Fieldset'], ] ); From 38b8045832764ed278c084307a369de79a319022 Mon Sep 17 00:00:00 2001 From: j3nsch Date: Mon, 4 May 2026 21:08:57 +0200 Subject: [PATCH 7/9] #867 Use activatedLanguages for UI language option --- modules/setup/controllers/LanguageController.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/setup/controllers/LanguageController.php b/modules/setup/controllers/LanguageController.php index 41a2f3b3a..7409d9fa5 100644 --- a/modules/setup/controllers/LanguageController.php +++ b/modules/setup/controllers/LanguageController.php @@ -492,7 +492,7 @@ public function settingsAction() // TODO provide form with options config $form = new Admin_Form_Configuration([ - 'supportedLanguages' => [ + 'activatedLanguages' => [ 'type' => 'supportedLanguages', 'section' => 'general', ], @@ -525,7 +525,7 @@ public function settingsAction() $form->populateFromModel($config); - $element = $form->getElement('supportedLanguages'); + $element = $form->getElement('activatedLanguages'); if (! isset($config->activatedLanguages)) { $element->setValue($config->supportedLanguages); } From 47059b21a0614f9ba5a162cd01d14c1c501d9669 Mon Sep 17 00:00:00 2001 From: j3nsch Date: Tue, 5 May 2026 18:02:02 +0200 Subject: [PATCH 8/9] #867 Fix validation bug if no language is selected --- library/Application/Form/Element/SupportedLanguages.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Application/Form/Element/SupportedLanguages.php b/library/Application/Form/Element/SupportedLanguages.php index 00392334e..72cfbecc7 100644 --- a/library/Application/Form/Element/SupportedLanguages.php +++ b/library/Application/Form/Element/SupportedLanguages.php @@ -116,7 +116,7 @@ public function getLanguageOptions() */ public function setValue($value) { - if (! is_array($value)) { + if (! is_array($value) && $value !== null) { $values = array_map('trim', explode(',', $value)); } else { $values = $value; From bc36c8f0ba123a26475cdd36a51327e46c8d6aa7 Mon Sep 17 00:00:00 2001 From: j3nsch Date: Tue, 5 May 2026 18:02:43 +0200 Subject: [PATCH 9/9] #867 Fix only using active language --- composer.json | 2 +- library/Application/Bootstrap.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 236a65104..2de75308e 100644 --- a/composer.json +++ b/composer.json @@ -32,7 +32,7 @@ "opus4-repo/opus4-job": "^4.9", "opus4-repo/opus4-security": "^4.9", "opus4-repo/opus4-sword": "^4.9", - "opus4-repo/opus4-app-common": "^4.9", + "opus4-repo/opus4-app-common": "dev-main as 4.10", "opus4-repo/opus4-deepgreen": "^4.9", "components/jquery": "3.4.*", "components/jqueryui": "1.12.*", diff --git a/library/Application/Bootstrap.php b/library/Application/Bootstrap.php index 1100dd953..d3b1d2783 100644 --- a/library/Application/Bootstrap.php +++ b/library/Application/Bootstrap.php @@ -260,7 +260,7 @@ protected function _setupPageCache() */ protected function _initTranslation() { - $this->bootstrap(['Configuration', 'Session', 'Logging', 'ZendCache']); + $this->bootstrap(['Configuration', 'OnlineConfiguration', 'Session', 'Logging', 'ZendCache']); $logService = LogService::getInstance(); $logger = $logService->getLog('translation');