From 5bb9990fd7c66723e9dd0e9f8ce253c7072fae9c Mon Sep 17 00:00:00 2001 From: Ralf Lang Date: Thu, 2 Jul 2026 21:04:48 +0200 Subject: [PATCH] fix(form): recognize Horde\{App}\...\FooVariable in BaseVariable::getTypeName() Restores {app}_form_type_{name} mapping for vendor-namespaced app variables so legacy Horde_Core_Ui_VarRenderer dispatch still finds the app's _renderVarInput_* methods. Surfaced by horde/ingo#34. --- src/V3/BaseVariable.php | 30 +++++++++++---- test/bootstrap.php | 4 ++ test/v3/V3BaseVariableTest.php | 18 +++++++++ test/v3/fixtures/GetTypeNameFixtures.php | 48 ++++++++++++++++++++++++ 4 files changed, 93 insertions(+), 7 deletions(-) create mode 100644 test/v3/fixtures/GetTypeNameFixtures.php diff --git a/src/V3/BaseVariable.php b/src/V3/BaseVariable.php index 4b3987a..b2e7f5f 100644 --- a/src/V3/BaseVariable.php +++ b/src/V3/BaseVariable.php @@ -341,17 +341,33 @@ public function getType() * @return string This variable's {@link Horde_Form_Type} name. * * Override with a simple return 'literal' string in your own types. - * - * @api + * + * The default derives the type name from the class namespace so app + * variables map back to their legacy `{app}_form_type_{name}` handles + * (used e.g. by `Horde_Core_Ui_VarRenderer::render()` when dispatching + * to `_renderVarInput_{typename}` methods). Three shapes are covered: + * + * - `Horde\Form\V3\FooVariable` → `foo` + * Vendor-owned horde/form variables use the bare name. + * - `Horde\{App}\...\FooVariable` → `{app}_form_type_foo` + * Vendor-namespaced app variables (PSR-4 `Horde\Ingo\Form\V3\…`). + * - `{App}\...\FooVariable` → `{app}_form_type_foo` + * Legacy pre-PSR-4 app variables (`Ingo\Form\V3\…`). + * + * @api */ public function getTypeName(): string { $parts = explode('\\', $this::class); - $app = strtolower($parts[0]); - $name = strtolower(substr($parts[count($parts) - 1], 0, -8)); - if ($app !== 'horde') { - // legacy - $name = $app . '_form_type_' . $name; + $name = strtolower(substr($parts[count($parts) - 1], 0, -8)); + $vendor = strtolower($parts[0]); + if ($vendor !== 'horde') { + // Legacy pre-PSR-4 app layout: `{App}\...\FooVariable`. + return $vendor . '_form_type_' . $name; + } + if (count($parts) >= 3 && strtolower($parts[1]) !== 'form') { + // Vendor-namespaced app layout: `Horde\{App}\...\FooVariable`. + return strtolower($parts[1]) . '_form_type_' . $name; } return $name; } diff --git a/test/bootstrap.php b/test/bootstrap.php index 756242a..c1ae8b6 100644 --- a/test/bootstrap.php +++ b/test/bootstrap.php @@ -7,6 +7,10 @@ // Load Composer autoloader require_once __DIR__ . '/../vendor/autoload.php'; +// Fixture classes declared in namespaces that PSR-4 autoloading in test/ +// cannot express (see BaseVariable::getTypeName() coverage). +require_once __DIR__ . '/v3/fixtures/GetTypeNameFixtures.php'; + // Setup minimal global mocks for Horde dependencies // These are needed by Horde_Form when form tokens are enabled diff --git a/test/v3/V3BaseVariableTest.php b/test/v3/V3BaseVariableTest.php index 9b68cb5..687ebd0 100644 --- a/test/v3/V3BaseVariableTest.php +++ b/test/v3/V3BaseVariableTest.php @@ -175,6 +175,24 @@ public function testGetTypeName(): void $this->assertEquals('text', $var->getTypeName()); } + public function testGetTypeNameForVendorNamespacedAppVariable(): void + { + // `Horde\Fakeapp\Form\V3\FoldersVariable` — modern PSR-4 app layout. + // See test/v3/fixtures/GetTypeNameFixtures.php. + $var = new \Horde\Fakeapp\Form\V3\FoldersVariable('Folder', 'folder', false); + + $this->assertEquals('fakeapp_form_type_folders', $var->getTypeName()); + } + + public function testGetTypeNameForLegacyAppVariable(): void + { + // `Fakeapp\Form\V3\FoldersVariable` — pre-PSR-4 legacy app layout. + // See test/v3/fixtures/GetTypeNameFixtures.php. + $var = new \Fakeapp\Form\V3\FoldersVariable('Folder', 'folder', false); + + $this->assertEquals('fakeapp_form_type_folders', $var->getTypeName()); + } + public function testIsRequired(): void { $requiredVar = new TextVariable('Name', 'name', true); diff --git a/test/v3/fixtures/GetTypeNameFixtures.php b/test/v3/fixtures/GetTypeNameFixtures.php new file mode 100644 index 0000000..5e69c7a --- /dev/null +++ b/test/v3/fixtures/GetTypeNameFixtures.php @@ -0,0 +1,48 @@ +