Notes on converting apps from Horde 5 to Horde 6
These are by far not complete. Last updated: 2026-03-04
||~ Package ||~ Strategy ||~ Unit Tests ||~ PHPStan ||~ PHP 8 ||~ Comments/Upgrade path ||
|| horde/alarm|| Legacy || 9.5 || Yes || Yes || Tests for unnamespaced modernized. Actual PSR-4 upgrade postponed, should use PSR-3 logger and modernized SQL when available ||
|| horde/argv|| Parallel || 9.5, 447 tests || Yes || Yes || Modern API complete with contextual option groups. See argv-contextual-option-groups-implementation-complete.md ||
|| horde/components || Wrapper || 9.4, Story tests broken || Yes || Yes || Lots of new features related to git, composer and workflows. Still maintains package.xml and requires it in some places. 219 src/, 5 lib/ ||
|| horde/horde-installer-plugin|| Modern || 9.5, very limited || Yes || Yes || Handles all the horde setup stuff, symlinks, workaround configs etc. 33 src/, 0 lib/ ||
|| horde/horde-deployment|| Modern || n/a || n/a || Yes || The base project for a horde installation with default dir tree - Branches reflect bundles ||
|| horde/hordectl || Modern || 9.5 || No || Yes || CLI management tool. 41 src/, 0 lib/ ||
|| horde/http_server || Modern || 9.5, only stub of a test framework || Yes || yes || Successor to horde/controller. 13 src/, 0 lib/ ||
|| horde/http || Parallel || 9.4 || No || yes || Major BC breaks. Implementation based on PSR-7, PSR-18. 28 src/, 17 lib/ ||
|| horde/injector || Wrapper || 9.5 || Yes || yes || Carefully added signatures, limited BC breaks for child injectors. Now PSR-11. 11 src/, 11 lib/ ||
|| horde/crypt_blowfish || Legacy || 9.5 || No || yes || works with openssl 3 ||
|| horde/controller || Keep || 9.4 || No || Yes || Only added namespaced wrapper code for interop with horde/http_server and PSR-7. 2 src/, 22 lib/ ||
|| horde/stream_wrapper || Parallel || 9.4 || No || yes || Class names have Wrapper appended to make sense when USEd. 8 src/, 7 lib/ ||
|| horde/util || Parallel || 9.5 || No || yes || Slightly renamed classes and typing upgrades. 9 src/, 7 lib/ ||
|| horde/text_diff || Parallel || 9.5 || No || yes, 8.2beta || Renamed classes, typing upgrades. 20 src/, 19 lib/ ||
|| horde/support|| Parallel || 9.4 || No || yes || Slightly renamed classes and typing upgrades. 10 src/, 15 lib/ ||
|| horde/compress_fast || Parallel || 9.4 || No || yes || Straight. 8 src/, 7 lib/ ||
|| horde/mongo || Parallel || 9.4 || No || yes || Removed support for the older extension - Still using the compat library. 7 src/, 6 lib/ ||
|| horde/cli || Parallel || 9.4 || No || yes || straight. 10 src/, 3 lib/ ||
|| horde/memcache || Parallel || 9.4, started minimal test suite || No || yes || straight. 15 src/, 22 lib/ ||
|| horde/cache || Parallel || 9.4, started minimal test suite || No || yes || Dropped some dead in-memory caches. 16 src/, 17 lib/ ||
|| horde/test || Parallel || 9.4, started minimal test suite || No || yes || straight. 14 src/, 8 lib/ ||
|| horde/routes || Parallel || 9.4 || No || yes || straight. 11 src/, 10 lib/ ||
|| horde/db || Parallel || 9.4 || No || yes || src/ Still a WIP mess. Dropped support for classic mysql extension. 42 src/, 41 lib/ ||
|| horde/log || Parallel || 9.4 || No || yes || Incompatible new design based on PSR-3, See ((Doc/Dev/HordeLog)). 17 src/, 8 lib/ ||
|| horde/thrift || Keep || n/a || n/a || yes || Only nominally released as a leaf dependency, may be deprecated ||
|| horde/scribe || Keep || n/a || n/a || yes || Only nominally released as a leaf dependency, may be deprecated ||
|| horde/translation || Parallel || 9.5, covers only lib/ || No || yes || Slightly renamed classes and typing upgrades. 6 src/, 5 lib/ ||
|| horde/exception || Parallel || 9.5 || No || yes || Slightly renamed classes and typing upgrades, better support for 3rd argument. 12 src/, 7 lib/ ||
|| horde/eventdispatcher || Modern || 9.5, Stub only || Yes || yes || PSR-14 replacement for PubSub, See ((Doc/Dev/HordeEventDispatcher)). 2 src/, 0 lib/ ||
|| horde/skeleton || Modern || 9.5, Stub Only || No || testing || Example app. 11 src/, 0 lib/ ||
|| horde/share || Legacy || 9.5, covers only /lib || No || yes, wip || Tests are not really run for the DB specific drivers yet but signatures check out. 0 src/, 44 lib/ ||
|| horde/kolab_format || Legacy || 9.5, covers only /lib || No || yes, wip || Little interest beyond making test suites for other libs work. 0 src/, 79 lib/ ||
|| horde/kolab_storage || Legacy || 9.5, covers only /lib || No || yes, wip || Little interest beyond making test suites for other libs work. 0 src/, 119 lib/ ||
|| horde/cli_modular || Parallel || 9.5, covers only /lib || No || yes, wip || Lib/ needs some minor fixes for PHP 8.1 compat. src/ is a major rewrite to account for modern autoloading, dependency injection, much more typing and lessons learned from cli_modular applications. 8 src/, 6 lib/ ||
|| horde/form || Parallel || 9.5 || Yes || Yes || Major modernization with typed code and PSR compliance. 61 src/, 14 lib/ ||
|| horde/constraint || Parallel || 9.5 || No || Yes || PSR-4 conversion complete. 14 src/, 11 lib/ ||
|| horde/secret || Modern || 9.5 || Yes || Yes || New implementation. 10 src/, 0 lib/ ||
|| horde/token || Modern || 9.5 || Yes || Yes || New implementation. 13 src/, 0 lib/ ||
|| horde/url || Parallel || 9.5 || No || Yes || PSR-4 conversion. 4 src/, 3 lib/ ||
|| horde/version || Modern || 9.5 || Yes || Yes || New semver implementation. 18 src/, 0 lib/ ||
|| horde/composer || Modern || 9.5 || Yes || Yes || Composer utilities. 13 src/, 0 lib/ ||
|| horde/githubapiclient || Modern || 9.5 || Yes || Yes || GitHub API v3 client. 68 src/, 0 lib/ ||
|| horde/hordeymlfile || Modern || 9.5 || Yes || Yes || .horde.yml parser. 8 src/, 0 lib/ ||
||~ App ||~ Strategy ||~ PHPUnit ||~ Status ||
|| horde/base || Parallel || Yes || 4 src/, 44 lib/ ||
|| horde/imp || Parallel || Yes || 1 src/, 318 lib/ - Major work needed ||
|| horde/ingo || Legacy || Yes || 0 src/, 118 lib/ ||
|| horde/kronolith || Parallel || Yes || 11 src/, 109 lib/ ||
|| horde/turba || Legacy || Yes || 0 src/, 52 lib/ ||
|| horde/nag || Parallel || Yes || 1 src/, 46 lib/ ||
|| horde/mnemo || Legacy || Yes || 0 src/, 26 lib/ ||
|| horde/ansel || Parallel || Yes || 1 src/, 93 lib/ ||
|| horde/whups || Parallel || No || 4 src/, 99 lib/ ||
|| horde/wicked || Parallel || Yes || 13 src/, 27 lib/ ||
|| horde/passwd || Parallel || Yes || 1 src/, 27 lib/ ||
|| horde/gollem || Parallel || No || 1 src/, 14 lib/ ||
|| horde/jonah || Parallel || Yes || 1 src/, 29 lib/ ||
|| horde/sesha || Legacy || Yes || 0 src/, 27 lib/ ||
|| horde/trean || Parallel || No || 1 src/, 21 lib/ ||
++ Parallel
Parallel strategy means double maint. burden but high freedom for due improvements and necessary BC breaks.
Example: horde/test, horde/cache, horde/cli
Current Count: ~40 libraries using Parallel strategy
++ Wrapper
Wrapper strategy allows both old and new calling code to leverage the same slightly modernized code base. However, BC breaks must be prevented.
Example: horde/components, horde/injector
Current Count: ~3 libraries using Wrapper strategy (components, injector, cli_application)
++ Modern
Newly developed code should only focus on the composer use case
Example: horde/horde-installer-plugin, horde/http_server, horde/hordectl, horde/skeleton
Current Count: ~15 libraries using Modern strategy (new implementations)
++ Legacy / Keep
Libraries which are essentially deprecated but kept around for H6, or not yet converted
Example: horde/controller (Keep), horde/alarm (Legacy but functional)
Current Count: ~90 libraries still in Legacy mode (0 src/ files)
++ Exceptions to the rule
++ Mandatory
Horde:: is deprecated [NO REAL REPLACEMENT YET - Still in planning]
[rla thinks] we should adopt PSR-2, PSR-12 wholesale with an optional opt-out for protected/private underscoring [IMPLEMENTED in Modern libraries]
Composer based setup must work with all libraries we intend to keep [SOLVED - All H6 libs have composer.json]
[rla thinks] Deprecate Horde_Forms usage. Keep it where it is until we can refactor, but make it clear this is a legacy concept
Update Horde_Core to support both namespaced apps non-namespaced apps and mixed. [ONGOING - Core has 44 src/, 280 lib/]
Update Horde_Test to support namespaced unit tests (PHPUnit 9 spews warnings for unit test classnames different than file name, so there is little use in BC here) [DONE]
Unit Tests must support the current stable phpunit [DONE - Most libs using PHPUnit 9.x+]
Check all pear package dependencies if they are also available via packagist or a proper composer channel rather than pear [MOSTLY DONE]
Update skeleton to use
++ Optional / Best Practice
++ Exceptions To The Rule
The home namespace for a library is $Vendor$Name, e.g. Horde\View
The home namespace for a subtype library is $Vendor$Parent$Name e.g. Horde\Xml\Element rather than Horde\Xml_Element
The Home Namespace for an app in $Horde$Name, e.g. Horde\Turba
The Horde Base app is Horde\Base
If a library has an interface or base class Horde_$Name, promote it to either:
Horde:: is Horde\Core\Horde:: though I think we should re-think using it at all
Un-namespaced controllers go to app\controllers\ dir, namespaced controllers just go anywhere under src/, i.e. src/Middleware, src/Handler, src/Controller with no magic attached.
Un-namespaced library code goes to lib/
New or converted namespaced library code goes to src/.
++ Optional
++ Exceptions to the rule
Remember Liskov:
++ Mandatory
++ Optional
++ Exceptions to the rule
++ Whitelist
For $injector:
Horde\Core\Registry
For $_GET, $_POST, $_REQUEST
Horde\Controller\
Horde\Routes\
Horde\Core\
Horde\Rpc\
Horde\Base\
Horde\Cli\
for $config:
for $page_output:
for $__autoload
++ Mandatory
++ Optional
++ Exceptions to the rule
As Horde has evolved over the years, we have different types of classes, sometimes even mixed.
++ Mandatory
Constructors SHOULD depend on interfaces or base classes, not on the (single) implementation.
HordeBase or App configuration SHOULD be depended on as TODO object, not as array and explicitly not via global state
Apps must not care for configuration of other apps, only theirs or HordeBase
Namespaced app-internal objects which implement an interface should be registered with the injector using the class combined with ::class, e.g.
// Use a factory to get an implementation
// In case the factory cannot be autowired itself, you need to register how to get it first.
$injector->bindFactory(Horde\Kronolith\Calendar\Resource::class, Horde\Kronolith\Calendar\Factory::class, 'create')
// In case you want a specific implementation and it can be autowired, just bind it.
$injector->bindImplementation(Horde\Kronolith\Renderer::class, Horde\Kronolith\Renderer\Default::class);
use Horde\Kronolith\Calendar\Resource;
use Horde\Kronolith\Calendar\Factory as CalendarFactory;
use Horde\Kronolith\Renderer;
use Horde\Kronolith\Renderer\Default as RendererDefault;
// Use a factory to get an implementation
// In case the factory cannot be autowired itself, you need to register how to get it first.
$injector->bindFactory(Resource::class, CalendarFactory::class, 'create')
// In case you want a specific implementation and it can be autowired, just bind it.
$injector->bindImplementation(Renderer::class, RendererDefault::class);
$injector->bindImplementation('Forms', '\Horde_Forms_Base');
++ Optional
++ Exceptions to the rule
++ Required
include, require and require_once should only ever happen to setup autoloading or as part of the autoloader or related to non-php code (templates, data)
make all explicit require/require_once check if the required class is already available for loading.
At least for now, we should not drop Horde\Autoloader
Horde\Autoloader must always act AFTER the composer autoloader, not first
++ Optional
++ UNCLEAR
++ horde\imp
++ Horde\Injector
++ Optional
++ Horde\Date
++ Optional
++ Horde\Core
Mandatory:
Optional:
++ Horde\Rpc
Mandatory:
Apart from mandatory changes, we should not currently port all horde to the new standard quickly.
++ Mandatory
++ Optional
++ Exception to the rule
++ Required
++ Optional