Skip to content

Improve identity driver class resolution logic#110

Merged
ralflang merged 1 commit into
FRAMEWORK_6_0from
fix/identity_driver_class_resolution
May 20, 2026
Merged

Improve identity driver class resolution logic#110
ralflang merged 1 commit into
FRAMEWORK_6_0from
fix/identity_driver_class_resolution

Conversation

@TDannhauer

Copy link
Copy Markdown
Contributor

Summary

Fix application-specific identity driver resolution in Horde_Core_Factory_Identity so drivers whose class names use an uppercase application prefix (notably IMP) are found reliably, including when the identity class has not yet been autoloaded.

Problem

When code requests an application identity via Horde_Core_Factory_Identity::create(null, $driver), the factory builds the class name as:

Horde_String::ucfirst($driver) . '_Prefs_Identity';

For the imp driver this yields Imp_Prefs_Identity, while the actual class defined in IMP is IMP_Prefs_Identity.

That mismatch surfaces as:

Cannot create IMP_Identity
  Root cause: imp identity driver does not exist.

When it shows up

The failure is easiest to reproduce on a "cold" request where IMP_Prefs_Identity has not been loaded yet:

  • Navigating to another app (e.g. Ingo) in smart mobile / responsive view while IMP code still needs IMP_Identity
  • Cross-app calls (registry, topbar, hooks) that touch IMP before IMP's autoload path has registered
  • Any path that calls IMP_Factory_IdentityHorde_Core_Factory_Identity::create(null, 'imp') without a prior full IMP page load

Once IMP_Prefs_Identity is loaded, PHP's case-insensitive class aliases can mask the bug, which makes it intermittent and environment-dependent.

Root cause

Driver Old resolved class Actual class
imp Imp_Prefs_Identity IMP_Prefs_Identity

class_exists('Imp_Prefs_Identity') returns false until the real class file is loaded. Composer's classmap indexes IMP_Prefs_Identity, not Imp_Prefs_Identity, so autoload does not help for the wrong name.

Solution

Extend the default branch of create() to:

  1. Try multiple class name conventionsucfirst($driver) and strtoupper($driver) before failing.
  2. Explicitly load the identity driver file — if no class is found, require_once {fileroot}/lib/Prefs/Identity.php from the registry and re-check both candidates with class_exists(..., false).

This keeps existing behaviour for normal apps (kronolithKronolith_Prefs_Identity) and fixes acronym-style apps (impIMP_Prefs_Identity) without hard-coding IMP.

Changes

File: lib/Horde/Core/Factory/Identity.php

Before (default branch):

$class = Horde_String::ucfirst($driver) . '_Prefs_Identity';
if (!class_exists($class)) {
    throw new Horde_Exception($driver . ' identity driver does not exist.');
}

After (default branch):

  • Resolve class via candidate list: {Ucfirst}_Prefs_Identity, {UPPER}_Prefs_Identity
  • Fallback: load {registry fileroot}/lib/Prefs/Identity.php if present
  • Only then throw "{driver} identity driver does not exist."

The special-case handling for driver === 'horde' (Bug #9936 / Horde_Prefs_HordeIdentity) is unchanged.

Test plan

  • Horde_Core_Factory_Identity::create(null, 'imp') returns IMP_Prefs_Identity on a fresh request (no prior IMP bootstrap).
  • $injector->getInstance('IMP_Identity') succeeds when IMP factories are bound.
  • Existing drivers still work: create(null, 'kronolith'), create() (default Horde_Core_Prefs_Identity), create(null, 'horde').
  • Invalid driver still throws: create(null, 'nonexistent_app').
  • Manual: open Ingo from smart mobile / responsive view while logged in; no IMP_Identity / "identity driver does not exist" errors in Horde log.

Suggested unit test (optional)

// After require bootstrap with registry + injector
$identity = $injector->getInstance('Horde_Core_Factory_Identity')->create(null, 'imp');
$this->assertInstanceOf('IMP_Prefs_Identity', $identity);

Backward compatibility

  • No API changes to Horde_Core_Factory_Identity::create().
  • No config changes required.
  • Apps with conventional {Ucfirst}_Prefs_Identity naming are unaffected.
  • Only apps using an all-caps prefix (currently IMP) gain correct resolution.

Related

  • Consumer: IMP_Factory_Identity in horde/imp calls create(null, 'imp').
  • Similar pattern may apply to other acronym app IDs if added in the future; this fix generalises via strtoupper($driver).

@TDannhauer TDannhauer requested a review from ralflang May 19, 2026 22:13
@ralflang

Copy link
Copy Markdown
Member

I see how this works now: This falls through to the horde Autoloader rather than composer autoloader because it tries to load a class name which doesn't exist.

The upper part of the fix is useful (try to accomodate the IMP special case) but I think we are over-doing it with the lower part.

Way forward:

  • Support a FQCN as input (string contains _ or )

  • Support a PSR-4 classname by convention

  • Support the IMP quirk (all-uppercase class name) - Already in your PR

  • I suggest we strip the attempt to do the autoloader's job and rather concentrate on trying to load the correct class name.

See horde/imp#43 and #110

Fixes: Autoloading IMP Prefs driver depends on legacy autoloader bindings
@ralflang ralflang force-pushed the fix/identity_driver_class_resolution branch from 68cf5a7 to 9a60f99 Compare May 20, 2026 07:09
@ralflang ralflang merged commit 16e5768 into FRAMEWORK_6_0 May 20, 2026
0 of 4 checks passed
@TDannhauer TDannhauer deleted the fix/identity_driver_class_resolution branch June 13, 2026 21:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants